"""ANU 직접 polling violation guard — task-2643 Track D.

PR #145 task-2642 박제 승격 (회장 verbatim · task md 7 acceptance):

1. bzaona6au 사건 명령 재현 → hook 가 반드시 deny
2. deny reason = "ANU_DIRECT_CI_POLLING_FORBIDDEN" 고정
3. deny payload 에 allowed_alternative="delegated_watcher_contract" 포함
4. deny payload 에 next_steps 안내 (watcher contract 가이드 포함)
5. fixture PROVENANCE 가 incident_ts_kst + 정책 feedback md 경로 명시
6. fixture evidence 가 정책 출처 + 이벤트 박제 경로 reference 포함
7. cross-link Track C fixture (`pr_145_bzaona6au_violation_replay`) 존재 + 동일 사건 박제

본 task-2643 의 PR scope 는 origin/main 에서 분기되므로 PR #145 산출물에 직접
경로 의존성을 두지 않는다. 대신 fixture 내부 박제 (evidence/PROVENANCE) 로 사건을
정합한다 (회장 verbatim · PR #145 혼합 0).
"""

import json
import sys
from pathlib import Path

_WT = Path(__file__).resolve().parents[2]
if str(_WT) not in sys.path:
    sys.path.insert(0, str(_WT))

from hooks.pre_tool_use_anu_guard import evaluate_tool_call  # noqa: E402

BZAONA6AU_FIXTURE = (
    _WT / "tests" / "fixtures" / "forbidden_bash_pattern" / "bzaona6au_violation_replay"
)
TRACK_C_CROSSLINK_FIXTURE = (
    _WT / "tests" / "fixtures" / "pr_open_watcher_wrapper" / "pr_145_bzaona6au_violation_replay"
)


def _load_fixture(base: Path):
    evidence = json.loads((base / "evidence.json").read_text(encoding="utf-8"))
    expected = json.loads((base / "expected.json").read_text(encoding="utf-8"))
    return evidence, expected


def test_acceptance_1_bzaona6au_replay_is_denied():
    """1. bzaona6au 사건 명령 재현 → hook deny."""
    evidence, _ = _load_fixture(BZAONA6AU_FIXTURE)
    decision = evaluate_tool_call(evidence["tool_call"])
    assert decision["decision"] == "deny"


def test_acceptance_2_deny_reason_is_canonical_constant():
    """2. deny reason = ANU_DIRECT_CI_POLLING_FORBIDDEN."""
    evidence, _ = _load_fixture(BZAONA6AU_FIXTURE)
    decision = evaluate_tool_call(evidence["tool_call"])
    assert decision["reason"] == "ANU_DIRECT_CI_POLLING_FORBIDDEN"


def test_acceptance_3_allowed_alternative_present():
    """3. allowed_alternative = delegated_watcher_contract."""
    evidence, _ = _load_fixture(BZAONA6AU_FIXTURE)
    decision = evaluate_tool_call(evidence["tool_call"])
    assert decision["allowed_alternative"] == "delegated_watcher_contract"


def test_acceptance_4_next_steps_guide_watcher_contract():
    """4. next_steps 가 watcher contract 작성을 안내."""
    evidence, _ = _load_fixture(BZAONA6AU_FIXTURE)
    decision = evaluate_tool_call(evidence["tool_call"])
    next_steps = decision.get("next_steps", [])
    assert isinstance(next_steps, list) and len(next_steps) >= 1
    joined = " ".join(next_steps)
    assert "watcher contract" in joined
    assert "callback" in joined or "dispatch" in joined


def test_acceptance_5_fixture_provenance_traces_incident():
    """5. PROVENANCE 가 incident ts + 정책 feedback md 경로 명시."""
    prov = (BZAONA6AU_FIXTURE / "PROVENANCE.md").read_text(encoding="utf-8")
    assert "2026-05-23" in prov
    assert "bzaona6au" in prov
    assert "feedback_anu_direct_polling_violation_pr_145_260523.md" in prov


def test_acceptance_6_fixture_evidence_references_policy_archives():
    """6. fixture evidence 가 정책 출처/이벤트 박제 경로를 참조."""
    evidence, _ = _load_fixture(BZAONA6AU_FIXTURE)
    ctx = evidence.get("context", {})
    # 정책 출처 명시
    assert ctx.get("policy_source", "").endswith(
        "feedback_anu_no_direct_ci_watch_use_handoff_260523.md"
    ) or "feedback_anu_no_direct_ci_watch_use_handoff" in str(ctx)
    # 위반 출처 명시
    assert "feedback_anu_direct_polling_violation_pr_145_260523.md" in str(ctx)
    # incident 발생 시각
    assert evidence.get("incident_ts_kst", "").startswith("2026-05-23")
    # claude-code task id
    assert evidence.get("violation_task_id_in_claude_code") == "bzaona6au"


def test_acceptance_7_track_c_crosslink_fixture_replays_same_incident():
    """7. Track C `pr_145_bzaona6au_violation_replay` 가 동일 사건을 PR-open level 에서 박제."""
    assert TRACK_C_CROSSLINK_FIXTURE.is_dir(), (
        f"missing Track C cross-link fixture: {TRACK_C_CROSSLINK_FIXTURE}"
    )
    ev, expected = _load_fixture(TRACK_C_CROSSLINK_FIXTURE)
    # 동일 사건 식별자
    assert ev["violation_task_id"] == "bzaona6au"
    assert ev["input"]["owner"] == "anu_main"
    # cross-link expected
    assert expected["exception_class"] == "OwnerImpersonationError"
    assert (
        expected.get("cross_link_track_d_fixture")
        == "tests/fixtures/forbidden_bash_pattern/bzaona6au_violation_replay/"
    )
