"""エントリポイント（`python -m tiasjudge`）．

`QApplication` を生成してメイン画面（SPEC_01）を表示する．
ログの出力先設定はエントリポイント側の責務とする（error-handling.md「ログ」）．

起動オプション:

- `--check`: 画面を生成して即終了する（起動可能性の確認用．イベントループを回さない）
- `--preview-result`: 結果画面（SPEC_01「結果画面」）だけをダミー結果で開く（デバッグ用）
- `--failed`: `--preview-result` と併用し，診断失敗パターンで開く
"""

from __future__ import annotations

import argparse
import logging
import sys
from collections.abc import Sequence
from typing import TYPE_CHECKING

import numpy as np

if TYPE_CHECKING:  # pragma: no cover - 型チェック時のみ
    from numpy.typing import NDArray
    from PySide6.QtWidgets import QApplication

    from tiasjudge.core.svm import DiagnosisResult

logger = logging.getLogger(__name__)

#: `--check`（イベントループを回さずに終了する）オプション
CHECK_OPTION = "--check"

#: ログの書式（診断の入出力は `core` が INFO で記録する）
LOG_FORMAT = "%(asctime)s %(levelname)s %(name)s: %(message)s"

# --- `--preview-result` 用のダミーデータ（デバッグ表示専用．診断は実行しない）---

#: プレビューに使うダミー画像の一辺（結果画面は 1/2 に縮小して表示する）
PREVIEW_IMAGE_SIZE = 400
#: プレビューに使うダミー画像の色（舌色に近い RGB）
PREVIEW_IMAGE_RGB = (198, 120, 120)
#: プレビューのダミー L*a*b*（学習データの範囲内にある代表値）
PREVIEW_LAB = (58.0, 24.0, 12.0)
#: 成功パターンのダミースコア（%）
PREVIEW_PERCENTAGES: dict[str, int] = {
    "purple": 5,
    "dark_red": 10,
    "crimson": 25,
    "pink": 55,
    "pale": 5,
}
#: 成功パターンの上位 2 色（`PREVIEW_PERCENTAGES` を降順に並べた先頭 2 件）
PREVIEW_TOP_LABELS = ("pink", "crimson")
#: 失敗パターンの上位 2 色（`LEGACY_FAILURE_PERCENTAGES` を降順に並べた先頭 2 件）
PREVIEW_FAILED_TOP_LABELS = ("purple", "pink")


def _build_parser() -> argparse.ArgumentParser:
    """コマンドライン引数のパーサを作る．"""
    parser = argparse.ArgumentParser(
        prog="tiasjudge",
        description="舌診支援システム（TIAS）を起動する．",
    )
    parser.add_argument(
        CHECK_OPTION,
        action="store_true",
        help="画面を生成して即終了する（起動可能性の確認用）",
    )
    parser.add_argument(
        "--preview-result",
        action="store_true",
        help="結果画面だけをダミー結果で開く（デバッグ用．診断は実行しない）",
    )
    parser.add_argument(
        "--failed",
        action="store_true",
        help="--preview-result と併用し，診断失敗パターンで開く",
    )
    return parser


def _preview_image() -> NDArray[np.uint8]:
    """プレビュー用の単色ダミー画像（BGR）を作る．"""
    red, green, blue = PREVIEW_IMAGE_RGB
    image = np.empty((PREVIEW_IMAGE_SIZE, PREVIEW_IMAGE_SIZE, 3), dtype=np.uint8)
    # OpenCV と同じ BGR 並びで埋める
    image[:, :] = (blue, green, red)
    return image


def _preview_result(*, failed: bool) -> DiagnosisResult:
    """プレビュー用のダミー診断結果を組み立てる（SVM 学習は行わない）．"""
    from tiasjudge.core.color import Lab
    from tiasjudge.core.csv_io import EVALUATION_COLUMN_COUNT
    from tiasjudge.core.svm import (
        LEGACY_FAILURE_PERCENTAGES,
        DiagnosisResult,
        FailureReason,
    )

    percentages = dict(LEGACY_FAILURE_PERCENTAGES) if failed else dict(PREVIEW_PERCENTAGES)
    top_labels = PREVIEW_FAILED_TOP_LABELS if failed else PREVIEW_TOP_LABELS
    return DiagnosisResult(
        lab=Lab(*PREVIEW_LAB),
        scores={key: value / 100 for key, value in percentages.items()},
        percentages=percentages,
        top_labels=top_labels,
        predictions=np.zeros(EVALUATION_COLUMN_COUNT, dtype=np.float32),
        failed=failed,
        failure_reason=FailureReason.OUT_OF_DOMAIN if failed else None,
    )


def _run_preview(app: QApplication, *, failed: bool, check: bool) -> int:
    """結果画面だけをダミー結果で開く（`--preview-result`）．"""
    # 関数内 import は起動時のみ GUI を読み込むため（`core` は GUI 非依存）
    from tiasjudge.gui.result_window import Language, ResultWindow, show_on_secondary_screen

    logger.info("結果画面のプレビューを開きます（failed=%s）", failed)
    window = ResultWindow(_preview_result(failed=failed), _preview_image(), Language.JAPANESE)
    if check:
        window.close()
        return 0

    # プレビューにはメイン画面が無いため，プライマリモニタを基準に別モニタを選ぶ
    show_on_secondary_screen(window, app.screens(), app.primaryScreen())
    return int(app.exec())


def main(argv: Sequence[str] | None = None) -> int:
    """アプリを起動する．戻り値はプロセスの終了コード．

    Args:
        argv: コマンドライン引数（プログラム名を含まない）．省略時は `sys.argv[1:]`．

    Returns:
        プロセスの終了コード（0 が正常終了）．
    """
    arguments = _build_parser().parse_args(list(sys.argv[1:] if argv is None else argv))
    logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)

    # GUI ツールキットの import は起動時のみに限定する（`core` は GUI 非依存）
    from PySide6.QtWidgets import QApplication

    app = QApplication.instance() or QApplication(sys.argv[:1])

    if arguments.preview_result:
        return _run_preview(app, failed=arguments.failed, check=arguments.check)

    from tiasjudge.gui.main_window import MainWindow

    window = MainWindow()
    if arguments.check:
        # 画面を構築できることだけを確認して終了する（ヘッドレス環境での確認用）
        window.close()
        return 0

    window.show()
    return int(app.exec())


if __name__ == "__main__":
    raise SystemExit(main())
