"""tests/poc/test_termination_classifier.py

Phase B 종료 분류 classifier 회귀 테스트.

⚠️ Dry-run only. 마커 파일 생성/dispatch 호출 검증 안 함 (classifier가 안 한다는 사실 자체를 테스트).
"""
# pyright: reportMissingImports=false
# (격리 POC. import는 conftest.py의 sys.path 등록을 통해 런타임 해결됨.
#  명령행 pyright는 pyrightconfig.json extraPaths로 0 errors. LSP 캐시 stale 대응.)
from __future__ import annotations

import json
from pathlib import Path

import pytest

from tools.poc.termination_classifier import (
    TaskEvidence,
    TerminationClassification,
    classify,
)

FIXTURES_DIR = Path(__file__).resolve().parents[2] / "memory" / "poc" / "termination_classifier" / "fixtures"
FIXTURE_FILES = [
    "task-2466.json",
    "task-2481.json",
    "task-2472+1.json",
    "task-2483.json",
    "task-2485.json",
]


def _load_fixture(filename: str) -> dict:
    path = FIXTURES_DIR / filename
    assert path.exists(), f"fixture not found: {path}"
    with path.open() as f:
        return json.load(f)


@pytest.mark.parametrize("fixture_name", FIXTURE_FILES)
def test_classification_matches_expected(fixture_name: str):
    """각 회귀 fixture의 expected_classification과 classifier 출력 일치 확인."""
    data = _load_fixture(fixture_name)
    expected = data.pop("expected_classification")
    # TaskEvidence가 모르는 키 제거 (예: _comment 등)
    valid_keys = TaskEvidence.__dataclass_fields__.keys()
    evidence_kwargs = {k: v for k, v in data.items() if k in valid_keys}
    evidence = TaskEvidence(**evidence_kwargs)

    result = classify(evidence)

    assert result.classification.value == expected, (
        f"{fixture_name}: expected {expected}, got {result.classification.value} "
        f"(rule={result.matched_rule})"
    )


def test_done_evidence():
    """직접 입력 케이스: DONE."""
    ev = TaskEvidence(
        task_id="test-done",
        pr_state="MERGED",
        pr_merged_at="2026-05-06T10:00:00Z",
        close_lifecycle_state="CLEAN",
        essence_verdict="PASS",
        forbidden_violations=0,
    )
    r = classify(ev)
    assert r.classification == TerminationClassification.DONE
    assert r.marker_file == ".done"


def test_unclassified_when_no_match():
    """모든 룰 미해당 시 UNCLASSIFIED."""
    ev = TaskEvidence(task_id="test-unknown")
    r = classify(ev)
    assert r.classification == TerminationClassification.UNCLASSIFIED
    assert r.confidence == 0.0


def test_priority_done_over_dogfooding():
    """DONE이 DOGFOODING_PENDING보다 우선 (close clean 시)."""
    ev = TaskEvidence(
        task_id="test-priority",
        pr_state="MERGED",
        pr_merged_at="2026-05-06T10:00:00Z",
        close_lifecycle_state="CLEAN",
        essence_verdict="PASS",
        ci_rollup="PASS",
        qc_result="PASS",
        forbidden_violations=0,
        dogfooding_external_dependency=True,  # DOGFOODING 조건도 만족
    )
    r = classify(ev)
    assert r.classification == TerminationClassification.DONE


def test_dry_run_no_side_effects(tmp_path, monkeypatch):
    """Classifier가 마커 파일 생성하지 않음을 보장."""
    # tmp_path를 cwd로 설정해 혹시라도 상대 경로 마커 생성 시도하면 잡힘
    monkeypatch.chdir(tmp_path)
    ev = TaskEvidence(
        task_id="test-side-effects",
        pr_state="MERGED",
        close_lifecycle_state="CLEAN",
    )
    classify(ev)
    # 마커 파일이 cwd에 생성되지 않아야 함
    assert list(tmp_path.iterdir()) == [], "classifier가 부수효과 발생시킴 (파일 생성)"


# ---------------------------------------------------------------------------
# 추가 단위 테스트 — 룰별 경계 조건 검증
# ---------------------------------------------------------------------------

def test_merge_pending_dependency_direct():
    """MERGE_PENDING_DEPENDENCY 직접 케이스: PR OPEN + essence PASS + dependency."""
    ev = TaskEvidence(
        task_id="test-merge-pending",
        pr_state="OPEN",
        essence_verdict="PASS",
        dependency_task_id="task-2472+2",
        ci_rollup="FAIL",
        retry_count=4,
        retry_max=3,
    )
    r = classify(ev)
    assert r.classification == TerminationClassification.MERGE_PENDING_DEPENDENCY
    assert "task-2472+2" in r.followup_conditions[0]


def test_merged_close_blocked_external_direct():
    """MERGED_CLOSE_BLOCKED_EXTERNAL 직접 케이스: PR MERGED + close FAIL + external blocker."""
    ev = TaskEvidence(
        task_id="test-close-blocked",
        pr_state="MERGED",
        pr_merged_at="2026-05-07T13:54:33Z",
        ci_rollup="PASS",
        close_lifecycle_state="FAIL",
        close_blocker_owner="external",
        forbidden_violations=0,
        admin_override_used=False,
        branch_protection_bypass=False,
    )
    r = classify(ev)
    assert r.classification == TerminationClassification.MERGED_CLOSE_BLOCKED_EXTERNAL
    assert r.marker_file == ".close-blocked-external"
    assert ".done" in r.preserve_markers
    assert ".escalate" in r.preserve_markers


def test_dogfooding_pending_direct():
    """DOGFOODING_PENDING 직접 케이스: PR MERGED + essence PASS + dogfooding 외부 의존."""
    ev = TaskEvidence(
        task_id="test-dogfooding",
        pr_state="MERGED",
        essence_verdict="PASS",
        ci_rollup="PASS",
        qc_result="WARN",
        close_lifecycle_state="NOT_RUN",
        dogfooding_external_dependency=True,
    )
    r = classify(ev)
    assert r.classification == TerminationClassification.DOGFOODING_PENDING
    assert r.marker_file == ".dogfooding-pending"
    assert len(r.followup_conditions) == 4


def test_merge_pending_open_no_essence_pass_not_classified():
    """PR OPEN이지만 essence PASS 없으면 MERGE_PENDING_DEPENDENCY 아님."""
    ev = TaskEvidence(
        task_id="test-open-no-pass",
        pr_state="OPEN",
        essence_verdict=None,
        dependency_task_id="task-9999",
    )
    r = classify(ev)
    assert r.classification != TerminationClassification.MERGE_PENDING_DEPENDENCY


def test_merged_close_blocked_not_triggered_with_internal_blocker():
    """close_blocker_owner == 'internal'이면 MERGED_CLOSE_BLOCKED_EXTERNAL 미해당."""
    ev = TaskEvidence(
        task_id="test-internal-blocker",
        pr_state="MERGED",
        pr_merged_at="2026-05-07T00:00:00Z",
        close_lifecycle_state="FAIL",
        close_blocker_owner="internal",
        forbidden_violations=0,
    )
    r = classify(ev)
    assert r.classification != TerminationClassification.MERGED_CLOSE_BLOCKED_EXTERNAL


def test_escalated_rule():
    """ESCALATED: retry 초과 + essence FAIL."""
    ev = TaskEvidence(
        task_id="test-escalated",
        retry_count=5,
        retry_max=3,
        essence_verdict="FAIL",
    )
    r = classify(ev)
    assert r.classification == TerminationClassification.ESCALATED
    assert r.marker_file == ".escalate"
