from __future__ import annotations

import copy
import json
from pathlib import Path

import pytest

from src.services.ai_agent_low_medium_risk_whitelist import (
    load_latest_ai_agent_low_medium_risk_whitelist,
)

_REPO_ROOT = Path(__file__).resolve().parents[3]
_COMMITTED_SNAPSHOT = (
    _REPO_ROOT
    / "docs"
    / "evaluations"
    / "ai_agent_low_medium_risk_whitelist_2026-06-18.json"
)


def test_load_latest_ai_agent_low_medium_risk_whitelist_reads_newest_file(tmp_path):
    older = _snapshot(generated_at="2026-06-17T00:00:00+08:00")
    newer = _snapshot(generated_at="2026-06-18T18:42:00+08:00")
    (tmp_path / "ai_agent_low_medium_risk_whitelist_2026-06-17.json").write_text(
        json.dumps(older),
        encoding="utf-8",
    )
    (tmp_path / "ai_agent_low_medium_risk_whitelist_2026-06-18.json").write_text(
        json.dumps(newer),
        encoding="utf-8",
    )

    loaded = load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)

    assert loaded["generated_at"] == "2026-06-18T18:42:00+08:00"
    assert loaded["program_status"]["current_task_id"] == "P2-408"
    assert loaded["program_status"]["next_task_id"] == "P2-409"
    assert loaded["program_status"]["read_only_mode"] is True
    assert loaded["rollups"]["low_risk_candidate_count"] == 3
    assert loaded["rollups"]["medium_risk_candidate_count"] == 3
    assert loaded["rollups"]["auto_worker_run_count"] == 0


def test_ai_agent_low_medium_risk_whitelist_requires_read_only_mode(tmp_path):
    snapshot = _snapshot()
    snapshot["program_status"]["read_only_mode"] = False
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="program_status"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_blocks_live_execution(tmp_path):
    snapshot = _snapshot()
    snapshot["whitelist_candidates"][0]["live_execution_allowed"] = True
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="live_execution_allowed"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_blocks_gateway_queue_write(tmp_path):
    snapshot = _snapshot()
    snapshot["activation_boundaries"]["gateway_queue_write_enabled"] = True
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="activation boundaries"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_requires_dry_run_verifier(tmp_path):
    snapshot = _snapshot()
    snapshot["whitelist_candidates"][0]["dry_run_verifier_id"] = "missing_verifier"
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="missing dry-run verifiers"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_requires_rollback_proof(tmp_path):
    snapshot = _snapshot()
    snapshot["whitelist_candidates"][0]["rollback_proof_id"] = "missing_rollback"
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="missing rollback proofs"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_requires_audit_reason_template(tmp_path):
    snapshot = _snapshot()
    snapshot["whitelist_candidates"][0]["audit_reason_template_id"] = "missing_audit_template"
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="missing audit reason templates"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_rejects_high_risk_candidate(tmp_path):
    snapshot = _snapshot()
    snapshot["whitelist_candidates"][0]["risk_tier"] = "high"
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="must be low or medium"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_requires_rollup_consistency(tmp_path):
    snapshot = _snapshot()
    snapshot["rollups"]["whitelist_candidate_count"] = 99
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="rollup counts"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_rejects_private_terms(tmp_path):
    snapshot = _snapshot()
    snapshot["whitelist_candidates"][0]["allowed_no_write_outputs"] = ["請把 In app browser 內容放進前端"]
    _write_snapshot(tmp_path, snapshot)

    with pytest.raises(ValueError, match="forbidden public terms"):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def test_ai_agent_low_medium_risk_whitelist_fails_when_missing(tmp_path):
    with pytest.raises(FileNotFoundError):
        load_latest_ai_agent_low_medium_risk_whitelist(tmp_path)


def _snapshot(*, generated_at: str = "2026-06-18T18:42:00+08:00") -> dict:
    payload = json.loads(_COMMITTED_SNAPSHOT.read_text(encoding="utf-8"))
    cloned = copy.deepcopy(payload)
    cloned["generated_at"] = generated_at
    return cloned


def _write_snapshot(tmp_path, payload: dict) -> None:
    (tmp_path / "ai_agent_low_medium_risk_whitelist_2026-06-18.json").write_text(
        json.dumps(payload),
        encoding="utf-8",
    )
