from pathlib import Path

import pytest

pytest.importorskip("tkinter")

import tkinter as tk  # noqa: E402

from fixtures.generate_fixtures import make_a4_pdf, make_password_pdf  # noqa: E402
from mints_prep.config import EvidenceStampConfig, FilenameConfig  # noqa: E402
from mints_prep.models import (  # noqa: E402
    Classification,
    FileRecord,
    FilenameFinding,
    FormatStatus,
    MetadataFinding,
    PdfFinding,
)
from mints_prep.processors.output_writer import PlannedCopy  # noqa: E402
from mints_prep.ui.review_logic import ReviewItem  # noqa: E402
from mints_prep.ui.write_review_dialog import WriteReviewDialog  # noqa: E402

_FILENAME_CONFIG = FilenameConfig(
    max_length=100,
    warning_length=50,
    forbidden_chars=("\\", "/", ":", "*", "?", '"', "<", ">", "|"),
    jis_x0213_codec="shift_jis_2004",
)
_STAMP_CONFIG = EvidenceStampConfig(font_size_pt=14, margin_top_mm=8, margin_right_mm=8)


@pytest.fixture(scope="module")
def root():
    r = tk.Tk()
    r.withdraw()
    yield r
    r.destroy()


def _record(path: Path, has_metadata: bool = False, pdf_finding=None) -> FileRecord:
    return FileRecord(
        path=path,
        size_bytes=path.stat().st_size if path.exists() else 100,
        format_status=FormatStatus.RECORD_READY,
        detected_format="PDF",
        classification=Classification.A_COMPLIANT,
        filename_finding=FilenameFinding(
            length=len(path.name), exceeds_max_length=False, exceeds_warning_length=False
        ),
        metadata_finding=MetadataFinding(has_metadata=has_metadata, detected_fields=("Author",) if has_metadata else ()),
        pdf_finding=pdf_finding,
    )


def test_confirm_applies_default_recommended_choices(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "甲001 契約書.pdf")
    record = _record(path, has_metadata=True)
    prelim = PlannedCopy(record=record, output_filename=path.name, strip_metadata=True, stamp_label="甲001")
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    assert set(dialog._choice_vars) == {"strip_metadata", "stamp"}
    assert all(v.get() for v in dialog._choice_vars.values())

    dialog._on_confirm()

    assert dialog.result.strip_metadata is True
    assert dialog.result.stamp_label == "甲001"
    assert not dialog.winfo_exists()


def test_unchecking_options_reverts_them(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "甲002 契約書.pdf")
    record = _record(path, has_metadata=True)
    prelim = PlannedCopy(record=record, output_filename=path.name, strip_metadata=True, stamp_label="甲002")
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()
    dialog._choice_vars["stamp"].set(False)

    dialog._on_confirm()

    assert dialog.result.strip_metadata is True
    assert dialog.result.stamp_label is None


def test_abort_returns_none_result(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "甲003.pdf")
    record = _record(path)
    prelim = PlannedCopy(record=record, output_filename=path.name)
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    dialog._on_abort()

    assert dialog.result is None
    assert not dialog.winfo_exists()


def test_password_protected_file_shows_no_stamp_option(root: tk.Tk, tmp_path: Path):
    path = make_password_pdf(tmp_path / "甲004 パスワード付き.pdf")
    record = _record(path, pdf_finding=PdfFinding(has_password=True))
    prelim = PlannedCopy(record=record, output_filename=path.name)
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    assert dialog._choice_vars == {}
    assert dialog._preview_photo is None

    dialog.destroy()


def test_preview_shows_stamp_by_default_when_stamp_checkbox_defaults_on(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "甲005 契約書.pdf")
    record = _record(path)
    prelim = PlannedCopy(record=record, output_filename=path.name, stamp_label="甲005")
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    # デフォルトでチェック済み（証拠番号スタンプ適用候補）のため、初期表示から
    # スタンプ適用後のプレビューが表示されているはず。
    assert dialog._preview_photo is not None
    initial_photo = dialog._preview_photo

    dialog._choice_vars["stamp"].set(False)
    root.update()

    # チェックを外すと、証拠番号を消去した（未適用の）プレビューに切り替わる。
    assert dialog._preview_photo is not None
    assert dialog._preview_photo is not initial_photo

    dialog._choice_vars["stamp"].set(True)
    root.update()

    assert dialog._preview_photo is not None

    dialog.destroy()


def test_position_controls_shown_when_stamp_option_present(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "甲006 契約書.pdf")
    record = _record(path)
    prelim = PlannedCopy(record=record, output_filename=path.name, stamp_label="甲006")
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    assert dialog._position_label is not None
    assert dialog._stamp_margin_top_mm == _STAMP_CONFIG.margin_top_mm
    assert dialog._stamp_margin_right_mm == _STAMP_CONFIG.margin_right_mm

    dialog.destroy()


def test_position_controls_not_shown_when_no_stamp_option(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "準備書面2.pdf")
    record = _record(path)
    prelim = PlannedCopy(record=record, output_filename=path.name)
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    assert dialog._position_label is None

    dialog.destroy()


def test_adjust_position_moves_stamp_and_updates_result(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "甲007 契約書.pdf")
    record = _record(path)
    prelim = PlannedCopy(record=record, output_filename=path.name, stamp_label="甲007")
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    initial_top = dialog._stamp_margin_top_mm
    initial_right = dialog._stamp_margin_right_mm
    initial_photo = dialog._preview_photo

    dialog._adjust_stamp_position(dy=1)  # 下方向へ移動（margin_top_mmが増える）
    root.update()

    assert dialog._stamp_margin_top_mm == initial_top + 2.0
    assert dialog._preview_photo is not None
    assert dialog._preview_photo is not initial_photo

    dialog._adjust_stamp_position(dx=1)  # 右方向へ移動（margin_right_mmが減る）
    root.update()

    assert dialog._stamp_margin_right_mm == initial_right - 2.0

    dialog._on_confirm()

    assert dialog.result.stamp_margin_top_mm == initial_top + 2.0
    assert dialog.result.stamp_margin_right_mm == initial_right - 2.0


def test_reset_position_restores_config_default(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "甲008 契約書.pdf")
    record = _record(path)
    prelim = PlannedCopy(record=record, output_filename=path.name, stamp_label="甲008")
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    dialog._adjust_stamp_position(dy=1, dx=1)
    root.update()
    assert dialog._stamp_margin_top_mm != _STAMP_CONFIG.margin_top_mm

    dialog._reset_stamp_position()
    root.update()

    assert dialog._stamp_margin_top_mm == _STAMP_CONFIG.margin_top_mm
    assert dialog._stamp_margin_right_mm == _STAMP_CONFIG.margin_right_mm

    dialog.destroy()


def test_position_does_not_go_negative(root: tk.Tk, tmp_path: Path):
    path = make_a4_pdf(tmp_path / "甲009 契約書.pdf")
    record = _record(path)
    prelim = PlannedCopy(record=record, output_filename=path.name, stamp_label="甲009")
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    small_config = EvidenceStampConfig(font_size_pt=14, margin_top_mm=1, margin_right_mm=1)
    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, small_config)
    root.update()

    dialog._adjust_stamp_position(dy=-5)  # 上方向へ大きく移動しようとしても0未満にはならない
    root.update()

    assert dialog._stamp_margin_top_mm == 0.0

    dialog.destroy()


def test_preview_toggle_not_wired_when_no_stamp_option(root: tk.Tk, tmp_path: Path):
    # 証拠番号処理の対象外ファイル（stamp_labelなし）では、チェックボックス
    # 自体が存在しないため、プレビューは常にスタンプなしの状態のまま。
    path = make_a4_pdf(tmp_path / "準備書面1.pdf")
    record = _record(path)
    prelim = PlannedCopy(record=record, output_filename=path.name)
    item = ReviewItem(preliminary=prelim, preview_record=record, batch_dir=tmp_path)

    dialog = WriteReviewDialog(root, item, 1, 1, _FILENAME_CONFIG, _STAMP_CONFIG)
    root.update()

    assert "stamp" not in dialog._choice_vars
    assert dialog._preview_photo is not None

    dialog.destroy()
