"""
P2-409 AI Agent controlled-apply / break-glass queue snapshot.

Loads the latest committed controlled-apply / critical break-glass queue. This
module validates read-only controlled apply packets, rejection guards, and
reviewer checklists. It does not run workers, send Telegram, write Gateway
queues, read secrets, call paid APIs, mutate hosts, run kubectl, or write
production state.
"""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from src.services.snapshot_paths import default_evaluations_dir

_DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__))
_SNAPSHOT_PATTERN = "ai_agent_high_risk_owner_review_queue_*.json"
_SCHEMA_VERSION = "ai_agent_high_risk_owner_review_queue_v1"
_RUNTIME_AUTHORITY = "controlled_apply_break_glass_queue_readback_no_live_execution"
_EXPECTED_CURRENT_TASK = "P2-409"
_EXPECTED_NEXT_TASK = "P2-410"
_EXPECTED_CANONICAL_ROOM = "AwoooI SRE 戰情室"
_EXPECTED_CANONICAL_ROOM_ENV = "SRE_GROUP_CHAT_ID"
_EXPECTED_SOURCE_SCHEMAS = {
    "ai_agent_low_medium_risk_whitelist_v1",
    "ai_agent_receipt_readback_owner_review_v1",
    "ai_agent_report_source_health_v1",
    "awoooi_work_items_report_source_gap_owner_review_v1",
    "telegram_notification_egress_inventory_v1",
    "telegram_notification_egress_owner_request_draft_v1",
}
_TRUE_TRUTH_FLAGS = {
    "p2_408_redirects_loaded",
    "p2_406b_receipt_owner_review_loaded",
    "p2_110d_report_source_gap_loaded",
    "p2_110e_work_items_owner_review_loaded",
    "telegram_egress_inventory_loaded",
    "telegram_owner_request_draft_loaded",
    "approval_packets_ready",
    "rejection_guards_ready",
    "reviewer_checklists_ready",
    "high_risk_controlled_apply_enabled",
    "critical_break_glass_required",
}
_FALSE_TRUTH_FLAGS = {
    "all_high_risk_actions_paused",
    "high_risk_owner_review_required",
    "auto_worker_enabled",
    "live_execution_enabled",
    "gateway_queue_write_enabled",
    "telegram_send_enabled",
    "bot_api_call_enabled",
    "receipt_production_write_enabled",
    "production_write_enabled",
    "secret_read_enabled",
    "paid_api_call_enabled",
    "host_write_enabled",
    "kubectl_action_enabled",
    "destructive_operation_enabled",
    "openclaw_replacement_allowed",
}
_ZERO_TRUTH_COUNTS = {
    "auto_worker_run_count_24h",
    "live_execution_count_24h",
    "gateway_queue_write_count_24h",
    "telegram_send_count_24h",
    "bot_api_call_count_24h",
    "receipt_production_write_count_24h",
    "production_write_count_24h",
    "secret_read_count_24h",
    "paid_api_call_count_24h",
    "host_write_count_24h",
    "kubectl_action_count_24h",
    "destructive_operation_count_24h",
    "owner_response_received_count_24h",
    "owner_response_accepted_count_24h",
    "redacted_payload_ingested_count_24h",
}
_TRUE_BOUNDARY_FLAGS = {
    "controlled_apply_queue_readback_allowed",
    "critical_break_glass_queue_readback_allowed",
    "approval_packet_preview_allowed",
    "rejection_guard_preview_allowed",
    "reviewer_checklist_allowed",
}
_FALSE_BOUNDARY_FLAGS = {
    "read_only_owner_review_queue_allowed",
    "auto_worker_enabled",
    "live_execution_enabled",
    "gateway_queue_write_enabled",
    "telegram_send_enabled",
    "bot_api_call_enabled",
    "receipt_production_write_enabled",
    "production_write_enabled",
    "secret_read_enabled",
    "paid_api_call_enabled",
    "host_write_enabled",
    "kubectl_action_enabled",
    "destructive_operation_enabled",
    "openclaw_replacement_allowed",
}
_ZERO_ROLLUP_FIELDS = {
    "owner_response_received_count",
    "owner_response_accepted_count",
    "owner_response_rejected_count",
    "redacted_payload_ingested_count",
    "auto_worker_run_count",
    "live_execution_count",
    "gateway_queue_write_count",
    "telegram_send_count",
    "bot_api_call_count",
    "receipt_production_write_count",
    "production_write_count",
    "secret_read_count",
    "paid_api_call_count",
    "host_write_count",
    "kubectl_action_count",
    "destructive_operation_count",
}
_FORBIDDEN_PUBLIC_TERMS = {
    "批准！繼續",
    "In app browser",
    "My request for Codex",
    "chain_of_thought",
    "chain-of-thought",
    "private reasoning text",
    "authorization_header",
    "authorization header value",
    "telegram token value",
    "raw prompt",
    "raw_payload",
}


def load_latest_ai_agent_high_risk_owner_review_queue(
    evaluations_dir: Path | None = None,
) -> dict[str, Any]:
    """Load the newest committed P2-409 controlled apply queue snapshot."""
    directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR
    candidates = sorted(directory.glob(_SNAPSHOT_PATTERN))
    if not candidates:
        raise FileNotFoundError(f"no AI Agent controlled apply queue snapshots found in {directory}")

    latest = candidates[-1]
    with latest.open(encoding="utf-8") as handle:
        payload = json.load(handle)

    if not isinstance(payload, dict):
        raise ValueError(f"{latest}: expected JSON object")

    label = str(latest)
    _require_schema(payload, label)
    _require_sources(payload, label)
    _require_queue_truth(payload, label)
    _require_queue_items(payload, label)
    _require_approval_packets(payload, label)
    _require_rejection_guards(payload, label)
    _require_reviewer_checklists(payload, label)
    _require_routing_policy(payload, label)
    _require_boundaries(payload, label)
    _require_rollups(payload, label)
    _require_no_forbidden_public_terms(payload, label)
    return payload


def _require_schema(payload: dict[str, Any], label: str) -> None:
    if payload.get("schema_version") != _SCHEMA_VERSION:
        raise ValueError(f"{label}: expected schema_version={_SCHEMA_VERSION}")
    status = payload.get("program_status") or {}
    expected = {
        "overall_completion_percent": 100,
        "current_priority": "P0",
        "current_task_id": _EXPECTED_CURRENT_TASK,
        "next_task_id": _EXPECTED_NEXT_TASK,
        "read_only_mode": True,
        "runtime_authority": _RUNTIME_AUTHORITY,
    }
    mismatches = _mismatches(status, expected)
    if mismatches:
        raise ValueError(f"{label}: program_status mismatch: {mismatches}")
    if not status.get("status_note"):
        raise ValueError(f"{label}: program_status.status_note is required")


def _require_sources(payload: dict[str, Any], label: str) -> None:
    if not payload.get("source_refs"):
        raise ValueError(f"{label}: source_refs must not be empty")
    sources = payload.get("source_readbacks") or []
    schemas = {item.get("source_schema_version") for item in sources}
    missing = sorted(_EXPECTED_SOURCE_SCHEMAS - schemas)
    if missing:
        raise ValueError(f"{label}: missing source schemas: {missing}")
    for item in sources:
        readback_id = item.get("readback_id") or "<missing>"
        for field in ("source_ref", "endpoint", "owner_agent", "status", "key_readback", "next_action"):
            if not item.get(field):
                raise ValueError(f"{label}: source readback {readback_id} missing {field}")


def _require_queue_truth(payload: dict[str, Any], label: str) -> None:
    truth = payload.get("queue_truth") or {}
    missing_true = sorted(flag for flag in _TRUE_TRUTH_FLAGS if truth.get(flag) is not True)
    if missing_true:
        raise ValueError(f"{label}: queue truth flags must remain true: {missing_true}")
    unsafe_false = sorted(flag for flag in _FALSE_TRUTH_FLAGS if truth.get(flag) is not False)
    if unsafe_false:
        raise ValueError(f"{label}: queue truth flags must remain false: {unsafe_false}")
    non_zero = sorted(field for field in _ZERO_TRUTH_COUNTS if truth.get(field) != 0)
    if non_zero:
        raise ValueError(f"{label}: queue live counts must remain zero: {non_zero}")
    if not truth.get("truth_note"):
        raise ValueError(f"{label}: queue_truth.truth_note is required")


def _require_queue_items(payload: dict[str, Any], label: str) -> None:
    items = payload.get("owner_review_queue_items") or []
    if len(items) < 1:
        raise ValueError(f"{label}: owner_review_queue_items must not be empty")
    risk_tiers = {item.get("risk_tier") for item in items}
    if not {"high", "critical"}.issubset(risk_tiers):
        raise ValueError(f"{label}: owner_review_queue_items must include high and critical items")
    for item in items:
        item_id = item.get("queue_item_id") or "<missing>"
        if item.get("risk_tier") not in {"high", "critical"}:
            raise ValueError(f"{label}: queue item {item_id} must be high or critical")
        if item.get("queue_status") not in {
            "controlled_apply_packet_ready",
            "critical_break_glass_required",
            "blocked_missing_owner_response",
            "approval_packet_preview_ready",
        }:
            raise ValueError(f"{label}: queue item {item_id} status is invalid")
        for field in (
            "source_readback_ids",
            "approval_packet_id",
            "rejection_guard_ids",
            "reviewer_checklist_ids",
            "required_owner_fields",
            "blocked_runtime_actions",
            "next_gate",
        ):
            if not item.get(field):
                raise ValueError(f"{label}: queue item {item_id} missing {field}")
        expected_owner_response = item.get("risk_tier") == "critical"
        if item.get("owner_response_required") is not expected_owner_response:
            raise ValueError(
                f"{label}: queue item {item_id}.owner_response_required must be "
                f"{expected_owner_response}"
            )
        for flag in ("rollback_owner_required", "postcheck_required"):
            if item.get(flag) is not True:
                raise ValueError(f"{label}: queue item {item_id}.{flag} must remain true")
        for flag in (
            "live_execution_allowed",
            "gateway_queue_write_allowed",
            "telegram_send_allowed",
            "production_write_allowed",
        ):
            if item.get(flag) is not False:
                raise ValueError(f"{label}: queue item {item_id}.{flag} must remain false")
        if item.get("side_effect_count") != 0:
            raise ValueError(f"{label}: queue item {item_id} side_effect_count must remain zero")


def _require_approval_packets(payload: dict[str, Any], label: str) -> None:
    packets = payload.get("approval_packets") or []
    packet_ids = {item.get("approval_packet_id") for item in packets}
    queue_packet_ids = {item.get("approval_packet_id") for item in payload.get("owner_review_queue_items") or []}
    missing = sorted(queue_packet_ids - packet_ids)
    if missing:
        raise ValueError(f"{label}: missing approval packets referenced by queue items: {missing}")
    queue_ids = {item.get("queue_item_id") for item in payload.get("owner_review_queue_items") or []}
    for packet in packets:
        packet_id = packet.get("approval_packet_id") or "<missing>"
        if packet.get("queue_item_id") not in queue_ids:
            raise ValueError(f"{label}: approval packet {packet_id} references unknown queue item")
        if packet.get("packet_status") not in {
            "controlled_apply_packet_ready",
            "break_glass_packet_ready",
            "blocked_missing_owner_response",
        }:
            raise ValueError(f"{label}: approval packet {packet_id} status is invalid")
        for field in ("required_owner_fields", "required_evidence_refs", "reviewer_checklist_id", "rejection_guard_ids"):
            if not packet.get(field):
                raise ValueError(f"{label}: approval packet {packet_id} missing {field}")
        for flag in ("rollback_owner_required", "postcheck_required"):
            if packet.get(flag) is not True:
                raise ValueError(f"{label}: approval packet {packet_id}.{flag} must remain true")
        for flag in (
            "sensitive_payload_allowed",
            "live_execution_allowed",
            "gateway_queue_write_allowed",
            "telegram_send_allowed",
            "production_write_allowed",
        ):
            if packet.get(flag) is not False:
                raise ValueError(f"{label}: approval packet {packet_id}.{flag} must remain false")


def _require_rejection_guards(payload: dict[str, Any], label: str) -> None:
    guards = payload.get("rejection_guards") or []
    guard_ids = {item.get("guard_id") for item in guards}
    referenced_ids = {
        guard_id
        for item in payload.get("owner_review_queue_items") or []
        for guard_id in (item.get("rejection_guard_ids") or [])
    } | {
        guard_id
        for item in payload.get("approval_packets") or []
        for guard_id in (item.get("rejection_guard_ids") or [])
    }
    missing = sorted(referenced_ids - guard_ids)
    if missing:
        raise ValueError(f"{label}: missing rejection guards referenced by packets or queue items: {missing}")
    for guard in guards:
        guard_id = guard.get("guard_id") or "<missing>"
        tiers = set(guard.get("applies_to_risk_tiers") or [])
        if not tiers or not tiers.issubset({"high", "critical"}):
            raise ValueError(f"{label}: rejection guard {guard_id} tiers are invalid")
        for field in ("rejection_condition", "blocked_runtime_actions", "reviewer_action"):
            if not guard.get(field):
                raise ValueError(f"{label}: rejection guard {guard_id} missing {field}")


def _require_reviewer_checklists(payload: dict[str, Any], label: str) -> None:
    checklists = payload.get("reviewer_checklists") or []
    checklist_ids = {item.get("checklist_id") for item in checklists}
    referenced_ids = {
        checklist_id
        for item in payload.get("owner_review_queue_items") or []
        for checklist_id in (item.get("reviewer_checklist_ids") or [])
    } | {item.get("reviewer_checklist_id") for item in payload.get("approval_packets") or []}
    missing = sorted(referenced_ids - checklist_ids)
    if missing:
        raise ValueError(f"{label}: missing reviewer checklists referenced by packets or queue items: {missing}")
    for checklist in checklists:
        checklist_id = checklist.get("checklist_id") or "<missing>"
        if not checklist.get("required_checks") or not checklist.get("pass_condition"):
            raise ValueError(f"{label}: reviewer checklist {checklist_id} missing checks or pass condition")
        for flag in ("approval_decision_allowed", "checklist_write_allowed"):
            if checklist.get(flag) is not False:
                raise ValueError(f"{label}: reviewer checklist {checklist_id}.{flag} must remain false")
        if checklist.get("side_effect_count") != 0:
            raise ValueError(f"{label}: reviewer checklist {checklist_id} side_effect_count must remain zero")


def _require_routing_policy(payload: dict[str, Any], label: str) -> None:
    policy = payload.get("routing_policy") or {}
    expected = {
        "high_risk_default_route": "controlled_apply_queue",
        "critical_risk_default_route": "critical_break_glass_queue",
        "low_medium_runtime_route": "controlled_apply_queue",
        "owner_response_required": False,
        "verbal_approval_accepted": False,
        "redacted_payload_only": True,
    }
    mismatches = _mismatches(policy, expected)
    if mismatches:
        raise ValueError(f"{label}: routing_policy mismatch: {mismatches}")


def _require_boundaries(payload: dict[str, Any], label: str) -> None:
    boundaries = payload.get("activation_boundaries") or {}
    missing_true = sorted(flag for flag in _TRUE_BOUNDARY_FLAGS if boundaries.get(flag) is not True)
    if missing_true:
        raise ValueError(f"{label}: activation boundaries must remain true: {missing_true}")
    unsafe_false = sorted(flag for flag in _FALSE_BOUNDARY_FLAGS if boundaries.get(flag) is not False)
    if unsafe_false:
        raise ValueError(f"{label}: activation boundaries must remain false: {unsafe_false}")

    telegram = payload.get("telegram_policy") or {}
    expected_telegram = {
        "canonical_room": _EXPECTED_CANONICAL_ROOM,
        "canonical_room_env": _EXPECTED_CANONICAL_ROOM_ENV,
        "gateway_queue_write_allowed": False,
        "direct_bot_api_allowed": False,
        "telegram_send_allowed": False,
        "receipt_write_allowed": False,
    }
    mismatches = _mismatches(telegram, expected_telegram)
    if mismatches:
        raise ValueError(f"{label}: telegram_policy mismatch: {mismatches}")

    redaction = payload.get("display_redaction_contract") or {}
    if redaction.get("redaction_required") is not True:
        raise ValueError(f"{label}: display redaction must remain required")
    for flag in (
        "unsafe_payload_display_allowed",
        "private_reasoning_display_allowed",
        "secret_value_display_allowed",
        "work_window_transcript_display_allowed",
    ):
        if redaction.get(flag) is not False:
            raise ValueError(f"{label}: display redaction flag {flag} must remain false")


def _require_rollups(payload: dict[str, Any], label: str) -> None:
    rollups = payload.get("rollups") or {}
    items = payload.get("owner_review_queue_items") or []
    packets = payload.get("approval_packets") or []
    guards = payload.get("rejection_guards") or []
    checklists = payload.get("reviewer_checklists") or []
    sources = payload.get("source_readbacks") or []
    blocked_actions = {
        *(
            action
            for item in items
            for action in (item.get("blocked_runtime_actions") or [])
        ),
        *(
            action
            for guard in guards
            for action in (guard.get("blocked_runtime_actions") or [])
        ),
    }
    blocked_actions.discard(None)
    expected = {
        "source_readback_count": len(sources),
        "queue_item_count": len(items),
        "high_risk_queue_count": sum(1 for item in items if item.get("risk_tier") == "high"),
        "critical_queue_count": sum(1 for item in items if item.get("risk_tier") == "critical"),
        "approval_packet_count": len(packets),
        "rejection_guard_count": len(guards),
        "reviewer_checklist_count": len(checklists),
        "approval_packet_required_count": len(items),
        "rejection_guard_required_queue_count": sum(1 for item in items if item.get("rejection_guard_ids")),
        "rollback_owner_required_count": sum(1 for item in items if item.get("rollback_owner_required") is True),
        "postcheck_required_count": sum(1 for item in items if item.get("postcheck_required") is True),
        "blocked_runtime_action_count": len(blocked_actions),
        "controlled_apply_queue_count": sum(1 for item in items if item.get("risk_tier") == "high"),
        "critical_break_glass_queue_count": sum(1 for item in items if item.get("risk_tier") == "critical"),
        "owner_response_required_count": sum(1 for item in items if item.get("owner_response_required") is True),
        "high_risk_owner_review_required_count": 0,
    }
    mismatches = {
        key: {"expected": value, "actual": rollups.get(key)}
        for key, value in expected.items()
        if rollups.get(key) != value
    }
    if mismatches:
        raise ValueError(f"{label}: rollup counts must match payload sections: {mismatches}")

    non_zero = sorted(field for field in _ZERO_ROLLUP_FIELDS if rollups.get(field) != 0)
    if non_zero:
        raise ValueError(f"{label}: live rollup counts must remain zero: {non_zero}")


def _require_no_forbidden_public_terms(payload: dict[str, Any], label: str) -> None:
    public_text = json.dumps(payload, ensure_ascii=False)
    lower_public_text = public_text.lower()
    leaked_terms = sorted(
        term
        for term in _FORBIDDEN_PUBLIC_TERMS
        if (term.lower() if term.isascii() else term) in lower_public_text
    )
    if leaked_terms:
        raise ValueError(f"{label}: forbidden public terms present: {leaked_terms}")


def _mismatches(actual: dict[str, Any], expected: dict[str, Any]) -> dict[str, dict[str, Any]]:
    return {
        key: {"expected": expected_value, "actual": actual.get(key)}
        for key, expected_value in expected.items()
        if actual.get(key) != expected_value
    }
