"""tests/regression/test_g3_fail_classification.py — T9: g3_fail 분류 + enum 4종.

헤임달 (개발2팀 테스트 엔지니어) 작성.
"""
from __future__ import annotations

import json
import os
import sys
from pathlib import Path

# worktree root 등록
_WT_ROOT = Path(__file__).resolve().parents[2]
if str(_WT_ROOT) not in sys.path:
    sys.path.insert(0, str(_WT_ROOT))

from utils.g3_fail_classifier import classify_g3_fail  # type: ignore[import]  # noqa: E402
from utils.state_repair import (  # type: ignore[import]  # noqa: E402
    RECONCILE_CLASSIFICATIONS,
    SUPPORTED_CLASSIFICATIONS,
)


# ---------------------------------------------------------------------------
# T9-A: classify_g3_fail multi-case
# ---------------------------------------------------------------------------


class TestClassifyG3Fail:
    def test_false_alert_resolved_by_late_report(self, tmp_path: Path):
        """report mtime > g3-fail mtime + fail_reasons에 'report not found'만 → false_alert."""
        g3_fail_path = tmp_path / "task-x.g3-fail"
        g3_fail_path.write_text(
            json.dumps({"fail_reasons": ["report not found"]}),
            encoding="utf-8",
        )
        # g3-fail mtime 먼저 설정 (과거)
        base_time = 1700000000.0
        os.utime(str(g3_fail_path), (base_time, base_time))

        report_path = tmp_path / "task-x.md"
        report_path.write_text("# task-x report\n", encoding="utf-8")
        # report mtime을 g3-fail 보다 늦게
        os.utime(str(report_path), (base_time + 60, base_time + 60))

        result = classify_g3_fail(g3_fail_path, report_path)
        assert result == "false_alert_resolved_by_late_report"

    def test_unresolved_when_report_missing(self, tmp_path: Path):
        """report 파일 없음 → unresolved."""
        g3_fail_path = tmp_path / "task-x.g3-fail"
        g3_fail_path.write_text(
            json.dumps({"fail_reasons": ["report not found"]}),
            encoding="utf-8",
        )

        report_path = tmp_path / "task-x.md"  # 존재하지 않음

        result = classify_g3_fail(g3_fail_path, report_path)
        assert result == "unresolved"

    def test_unresolved_when_report_older_than_g3fail(self, tmp_path: Path):
        """report mtime < g3-fail mtime → unresolved."""
        g3_fail_path = tmp_path / "task-x.g3-fail"
        g3_fail_path.write_text(
            json.dumps({"fail_reasons": ["report not found"]}),
            encoding="utf-8",
        )
        base_time = 1700000000.0
        # report가 더 오래됨
        report_path = tmp_path / "task-x.md"
        report_path.write_text("# task-x report\n", encoding="utf-8")
        os.utime(str(report_path), (base_time, base_time))
        # g3-fail이 report보다 최신
        os.utime(str(g3_fail_path), (base_time + 120, base_time + 120))

        result = classify_g3_fail(g3_fail_path, report_path)
        assert result == "unresolved"

    def test_unresolved_when_other_fail_reasons(self, tmp_path: Path):
        """fail_reasons에 'report not found' 외 다른 이유 → unresolved."""
        g3_fail_path = tmp_path / "task-x.g3-fail"
        g3_fail_path.write_text(
            json.dumps({"fail_reasons": ["test failure: exit code 1"]}),
            encoding="utf-8",
        )
        base_time = 1700000000.0
        os.utime(str(g3_fail_path), (base_time, base_time))

        report_path = tmp_path / "task-x.md"
        report_path.write_text("# task-x report\n", encoding="utf-8")
        os.utime(str(report_path), (base_time + 60, base_time + 60))

        result = classify_g3_fail(g3_fail_path, report_path)
        assert result == "unresolved"

    def test_unresolved_when_g3fail_missing(self, tmp_path: Path):
        """.g3-fail 파일 없음 → unresolved (fail-closed)."""
        g3_fail_path = tmp_path / "nonexistent.g3-fail"  # 존재하지 않음
        report_path = tmp_path / "task-x.md"
        report_path.write_text("# task-x report\n", encoding="utf-8")

        result = classify_g3_fail(g3_fail_path, report_path)
        assert result == "unresolved"


# ---------------------------------------------------------------------------
# T9-B: RECONCILE_CLASSIFICATIONS enum 4종 + SUPPORTED_CLASSIFICATIONS
# ---------------------------------------------------------------------------


class TestClassificationEnums:
    def test_4_classifications_defined(self):
        """4종 classification enum이 정확히 정의됨."""
        expected = {
            "state_orphaned_after_valid_merge",
            "state_corrupted_with_partial_merge",
            "state_inconsistent_after_force_push",
            "state_missing_after_taskctl_crash",
        }
        assert RECONCILE_CLASSIFICATIONS == expected

    def test_supported_subset(self):
        """1차 지원은 state_orphaned_after_valid_merge만."""
        assert SUPPORTED_CLASSIFICATIONS == {"state_orphaned_after_valid_merge"}
        assert SUPPORTED_CLASSIFICATIONS.issubset(RECONCILE_CLASSIFICATIONS)

    def test_unsupported_classification_via_cli_rejects(self):
        """subprocess로 cmd_reconcile 호출 — 미지원 classification → exit 1."""
        import subprocess

        result = subprocess.run(
            [
                sys.executable,
                str(_WT_ROOT / "scripts" / "taskctl.py"),
                "reconcile",
                "--task-id", "task-2472+1-test",
                "--classification", "state_corrupted_with_partial_merge",
                "--evidence", "pr=99",
                "--evidence", "merge-commit=abc1234",
                "--approved-by-chairman",
                "--evidence-path", "/tmp/dummy.jsonl",
            ],
            capture_output=True,
            text=True,
            timeout=30,
            env={**os.environ, "WORKSPACE_ROOT": str(_WT_ROOT)},
        )
        assert result.returncode != 0, (
            f"기대: exit 1, 실제: {result.returncode}\n"
            f"stdout: {result.stdout}\nstderr: {result.stderr}"
        )
        combined = result.stdout + result.stderr
        assert "enum 인식만 지원" in combined or "1차 실 동작" in combined, (
            f"예상 메시지 없음. combined output:\n{combined}"
        )
