"""
AI Agent result capture release verifier preflight gate snapshot.

Loads the latest committed P2-136 release verifier preflight gate.
This module validates committed evidence only; it never authorizes owner
release, approves maintenance windows, confirms rollback owners, passes
release authorization, releases live apply, applies writers, writes receipts,
writes result captures, writes learning records, updates PlayBook trust, writes
reviewer / Gateway queues, sends Telegram messages, reads secrets, or performs
destructive operations.
"""

from __future__ import annotations

import json
import re
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_result_capture_release_verifier_preflight_gate_*.json"
_SCHEMA_VERSION = "ai_agent_result_capture_release_verifier_preflight_gate_v1"
_RUNTIME_AUTHORITY = "result_capture_release_verifier_preflight_gate_only_no_live_write"


def load_latest_ai_agent_result_capture_release_verifier_preflight_gate(
    evaluations_dir: Path | None = None,
) -> dict[str, Any]:
    """Load the newest committed release verifier preflight gate."""
    directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR
    candidates = sorted(directory.glob(_SNAPSHOT_PATTERN))
    if not candidates:
        raise FileNotFoundError(f"no AI Agent result capture release verifier preflight gate 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_prior(payload, label)
    _require_truth(payload, label)
    _require_authorization_readbacks(payload, label)
    _require_rollback_readbacks(payload, label)
    _require_maintenance_holds(payload, label)
    _require_live_apply_holds(payload, label)
    _require_blocked_transitions(payload, label)
    _require_actions(payload, label)
    _require_display_redaction(payload, label)
    _require_no_forbidden_display_terms(payload, label)
    _require_rollup_consistency(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 = {
        "current_priority": "P2",
        "current_task_id": "P2-136",
        "next_task_id": "P2-137",
        "read_only_mode": True,
        "runtime_authority": _RUNTIME_AUTHORITY,
        "overall_completion_percent": 100,
    }
    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_prior(payload: dict[str, Any], label: str) -> None:
    prior = payload.get("prior_release_authorization_readback_gate") or {}
    expected = {
        "schema_version": "ai_agent_result_capture_release_authorization_readback_gate_v1",
        "release_authorization_readback_count": 5,
        "rollback_release_readback_count": 5,
        "maintenance_window_readback_hold_count": 5,
        "live_apply_release_readback_hold_count": 5,
        "blocked_release_readback_transition_count": 6,
        "operator_action_count": 5,
        "approval_required_total": 8,
        "blocked_total": 9,
        "owner_release_authorized_count": 0,
        "owner_release_approved_count": 0,
        "maintenance_window_approved_count": 0,
        "rollback_owner_confirmed_count": 0,
        "post_release_verifier_ready_count": 0,
        "final_release_candidate_approved_count": 0,
        "final_release_candidate_pass_count": 0,
        "release_authorization_granted_count": 0,
        "release_authorization_pass_count": 0,
        "rollback_release_pass_count": 0,
        "live_apply_release_pass_count": 0,
        "writer_apply_count": 0,
        "execution_apply_count": 0,
        "receipt_write_count": 0,
        "result_capture_write_count": 0,
        "learning_write_count": 0,
        "playbook_trust_write_count": 0,
        "reviewer_queue_write_count": 0,
        "gateway_queue_write_count": 0,
        "telegram_send_count": 0,
        "bot_api_call_count": 0,
        "report_receipt_write_count": 0,
    }
    mismatches = _mismatches(prior, expected)
    if mismatches:
        raise ValueError(f"{label}: prior_release_authorization_readback_gate mismatch: {mismatches}")
    if not prior.get("readiness_note"):
        raise ValueError(f"{label}: prior_release_authorization_readback_gate.readiness_note is required")


def _require_truth(payload: dict[str, Any], label: str) -> None:
    truth = payload.get("release_verifier_preflight_truth") or {}
    required_true = {
        "p2_135_release_authorization_readback_gate_loaded",
        "release_verifier_preflight_ready",
        "rollback_verifier_preflight_ready",
        "maintenance_window_verifier_hold_active",
        "live_apply_verifier_hold_active",
        "owner_authorization_review_still_required",
        "release_verifier_review_still_required",
        "rollback_owner_review_required",
        "redaction_review_required",
        "release_verifier_preflight_only",
    }
    missing = sorted(field for field in required_true if truth.get(field) is not True)
    if missing:
        raise ValueError(f"{label}: release verifier preflight flags must remain true: {missing}")

    required_false = {
        "owner_release_authorized",
        "owner_release_approved",
        "maintenance_window_approved",
        "rollback_owner_confirmed",
        "post_release_verifier_ready",
        "final_release_candidate_approved",
        "final_release_candidate_passed",
        "release_authorization_granted",
        "release_authorization_passed",
        "rollback_release_passed",
        "live_apply_release_passed",
        "writer_apply_enabled",
        "execution_apply_enabled",
        "receipt_write_enabled",
        "reviewer_queue_write_enabled",
        "gateway_queue_write_enabled",
        "telegram_send_enabled",
        "bot_api_call_enabled",
        "report_receipt_write_enabled",
        "result_capture_write_enabled",
        "learning_write_enabled",
        "playbook_trust_write_enabled",
        "production_write_enabled",
        "secret_read_enabled",
        "destructive_operation_enabled",
    }
    unsafe = sorted(field for field in required_false if truth.get(field) is not False)
    if unsafe:
        raise ValueError(f"{label}: release verifier preflight live/send/write flags must remain false: {unsafe}")

    zero_counts = {
        "owner_release_authorized_count",
        "owner_release_approved_count",
        "maintenance_window_approved_count",
        "rollback_owner_confirmed_count",
        "post_release_verifier_ready_count",
        "final_release_candidate_approved_count",
        "final_release_candidate_pass_count",
        "release_authorization_granted_count",
        "release_authorization_pass_count",
        "rollback_release_pass_count",
        "live_apply_release_pass_count",
        "writer_apply_count",
        "execution_apply_count",
        "receipt_write_count",
        "reviewer_queue_write_count",
        "gateway_queue_write_count",
        "telegram_send_count",
        "bot_api_call_count",
        "report_receipt_write_count",
        "result_capture_write_count",
        "learning_write_count",
        "playbook_trust_write_count",
        "production_write_count",
        "secret_read_count",
        "destructive_operation_count",
    }
    non_zero = sorted(field for field in zero_counts if truth.get(field) != 0)
    if non_zero:
        raise ValueError(f"{label}: release verifier preflight live counters must remain zero: {non_zero}")
    if not truth.get("truth_note"):
        raise ValueError(f"{label}: release_verifier_preflight_truth.truth_note is required")


def _require_authorization_readbacks(payload: dict[str, Any], label: str) -> None:
    items = payload.get("release_verifier_preflight_gates") or []
    _require_ids(
        items,
        "readback_id",
        {
            "release_verifier_preflight_result_capture",
            "release_verifier_preflight_learning",
            "release_verifier_preflight_playbook_trust",
            "release_verifier_preflight_reviewer_queue",
            "release_verifier_preflight_gateway_queue",
        },
        label,
        "release verifier preflights",
    )
    for item in items:
        item_id = item.get("readback_id")
        if item.get("readback_mode") != "release_verifier_preflight_gate":
            raise ValueError(f"{label}: release verifier preflight {item_id} mode is invalid")
        if item.get("owner_release_authorized") is not False:
            raise ValueError(f"{label}: release verifier preflight {item_id} must stay unauthorized")
        if item.get("release_authorization_granted") is not False or item.get("release_authorization_passed") is not False:
            raise ValueError(f"{label}: release verifier preflight {item_id} must stay ungranted and unpassed")
        _require_valid_status(item, label, f"release verifier preflight {item_id}")
        if not item.get("readback_summary") or not _is_redacted_sha256(item.get("evidence_hash")):
            raise ValueError(f"{label}: release verifier preflight {item_id} must include summary and redacted evidence_hash")


def _require_rollback_readbacks(payload: dict[str, Any], label: str) -> None:
    items = payload.get("rollback_verifier_preflight_gates") or []
    _require_count(items, 5, label, "rollback release readbacks")
    for item in items:
        item_id = item.get("readback_id")
        if item.get("readback_mode") != "rollback_verifier_preflight_gate":
            raise ValueError(f"{label}: rollback release readback {item_id} mode is invalid")
        if item.get("rollback_owner_required") is not True:
            raise ValueError(f"{label}: rollback release readback {item_id} must require rollback owner")
        if item.get("rollback_owner_confirmed") is not False or item.get("rollback_release_passed") is not False or item.get("rollback_release_enabled") is not False:
            raise ValueError(f"{label}: rollback release readback {item_id} must stay unconfirmed, unpassed, and disabled")
        _require_valid_status(item, label, f"rollback release readback {item_id}")
        if not item.get("readback_summary"):
            raise ValueError(f"{label}: rollback release readback {item_id}.readback_summary is required")


def _require_maintenance_holds(payload: dict[str, Any], label: str) -> None:
    items = payload.get("maintenance_window_verifier_holds") or []
    _require_count(items, 5, label, "maintenance window readback holds")
    for item in items:
        item_id = item.get("hold_id")
        if item.get("hold_mode") != "maintenance_window_verifier_hold":
            raise ValueError(f"{label}: maintenance window readback hold {item_id} mode is invalid")
        if item.get("owner_release_authorized") is not False or item.get("maintenance_window_approved") is not False:
            raise ValueError(f"{label}: maintenance window readback hold {item_id} must keep owner release and maintenance unapproved")
        if item.get("final_release_candidate_passed") is not False:
            raise ValueError(f"{label}: maintenance window readback hold {item_id} must keep final candidate unpassed")
        _require_valid_status(item, label, f"maintenance window readback hold {item_id}")
        if not item.get("hold_reason"):
            raise ValueError(f"{label}: maintenance window readback hold {item_id}.hold_reason is required")


def _require_live_apply_holds(payload: dict[str, Any], label: str) -> None:
    items = payload.get("live_apply_verifier_holds") or []
    _require_count(items, 5, label, "live apply release readback holds")
    for item in items:
        item_id = item.get("hold_id")
        if item.get("hold_mode") != "live_apply_verifier_hold":
            raise ValueError(f"{label}: live apply release readback hold {item_id} mode is invalid")
        if item.get("release_authorization_granted") is not False or item.get("release_authorization_passed") is not False:
            raise ValueError(f"{label}: live apply release readback hold {item_id} must stay ungranted and unpassed")
        if item.get("live_apply_release_passed") is not False or item.get("live_apply_release_enabled") is not False:
            raise ValueError(f"{label}: live apply release readback hold {item_id} must stay unpassed and disabled")
        _require_valid_status(item, label, f"live apply release readback hold {item_id}")
        if not item.get("release_condition"):
            raise ValueError(f"{label}: live apply release readback hold {item_id}.release_condition is required")


def _require_blocked_transitions(payload: dict[str, Any], label: str) -> None:
    items = payload.get("blocked_verifier_preflight_transitions") or []
    _require_count(items, 6, label, "blocked release readback transitions")
    critical_count = 0
    for item in items:
        item_id = item.get("blocker_id")
        if item.get("severity") == "critical":
            critical_count += 1
        if item.get("status") not in {"approval_required", "blocked_by_policy"}:
            raise ValueError(f"{label}: blocked release readback transition {item_id} status is invalid")
        if not item.get("blocked_action") or not item.get("blocked_until") or not _is_redacted_sha256(item.get("evidence_hash")):
            raise ValueError(f"{label}: blocked release readback transition {item_id} must include blocked action, until, and evidence hash")
    if critical_count != 5:
        raise ValueError(f"{label}: expected 5 critical release readback blockers, got {critical_count}")


def _require_actions(payload: dict[str, Any], label: str) -> None:
    items = payload.get("operator_actions") or []
    _require_count(items, 5, label, "operator actions")
    for item in items:
        item_id = item.get("action_id")
        if item.get("runtime_write_allowed") is not False:
            raise ValueError(f"{label}: operator action {item_id} must not allow runtime writes")
        if item.get("status") not in {"ready_for_operator_review", "approval_required"}:
            raise ValueError(f"{label}: operator action {item_id} status is invalid")
        if not item.get("operator_instruction"):
            raise ValueError(f"{label}: operator action {item_id}.operator_instruction is required")


def _require_display_redaction(payload: dict[str, Any], label: str) -> None:
    contract = payload.get("display_redaction_contract") or {}
    expected = {
        "redaction_required": True,
        "raw_prompt_display_allowed": False,
        "private_reasoning_display_allowed": False,
        "secret_value_display_allowed": False,
        "raw_runtime_payload_display_allowed": False,
        "internal_collaboration_content_display_allowed": False,
    }
    mismatches = _mismatches(contract, expected)
    if mismatches:
        raise ValueError(f"{label}: display_redaction_contract mismatch: {mismatches}")
    if not contract.get("frontend_display_policy"):
        raise ValueError(f"{label}: display_redaction_contract.frontend_display_policy is required")


def _require_no_forbidden_display_terms(payload: dict[str, Any], label: str) -> None:
    forbidden_terms = {
        "work_window_transcript",
        "session_id",
        "browser_context",
        "authorization_header",
        "raw Telegram payload",
        "private reasoning",
        "raw prompt",
        "chain-of-thought",
        "批准！繼續",
        "My request for Codex",
        "In app browser",
    }
    display_blob = json.dumps(
        {
            "program_status": payload.get("program_status"),
            "release_verifier_preflight_gates": payload.get("release_verifier_preflight_gates"),
            "rollback_verifier_preflight_gates": payload.get("rollback_verifier_preflight_gates"),
            "maintenance_window_verifier_holds": payload.get("maintenance_window_verifier_holds"),
            "live_apply_verifier_holds": payload.get("live_apply_verifier_holds"),
            "operator_actions": payload.get("operator_actions"),
            "display_redaction_contract": payload.get("display_redaction_contract"),
        },
        ensure_ascii=False,
    )
    leaked = sorted(term for term in forbidden_terms if term in display_blob)
    if leaked:
        raise ValueError(f"{label}: forbidden display terms leaked: {leaked}")


def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None:
    rollups = payload.get("rollups") or {}
    expected = {
        "release_verifier_preflight_count": 5,
        "rollback_verifier_preflight_count": 5,
        "maintenance_window_verifier_hold_count": 5,
        "live_apply_verifier_hold_count": 5,
        "blocked_verifier_preflight_transition_count": 6,
        "operator_action_count": 5,
        "approval_required_authorization_readback_count": 2,
        "blocked_authorization_readback_count": 1,
        "approval_required_rollback_readback_count": 2,
        "blocked_rollback_readback_count": 1,
        "approval_required_maintenance_window_count": 2,
        "blocked_maintenance_window_count": 1,
        "approval_required_live_apply_readback_count": 2,
        "blocked_live_apply_readback_count": 1,
        "critical_blocker_count": 5,
        "owner_release_authorized_count": 0,
        "owner_release_approved_count": 0,
        "maintenance_window_approved_count": 0,
        "rollback_owner_confirmed_count": 0,
        "post_release_verifier_ready_count": 0,
        "final_release_candidate_approved_count": 0,
        "final_release_candidate_pass_count": 0,
        "release_authorization_granted_count": 0,
        "release_authorization_pass_count": 0,
        "rollback_release_pass_count": 0,
        "live_apply_release_pass_count": 0,
        "writer_apply_count": 0,
        "execution_apply_count": 0,
        "receipt_write_count": 0,
        "reviewer_queue_write_count": 0,
        "gateway_queue_write_count": 0,
        "telegram_send_count": 0,
        "bot_api_call_count": 0,
        "report_receipt_write_count": 0,
        "result_capture_write_count": 0,
        "learning_write_count": 0,
        "playbook_trust_write_count": 0,
        "production_write_count": 0,
        "secret_read_count": 0,
        "destructive_operation_count": 0,
    }
    mismatches = _mismatches(rollups, expected)
    if mismatches:
        raise ValueError(f"{label}: rollups mismatch: {mismatches}")


def _require_valid_status(item: dict[str, Any], label: str, item_label: str) -> None:
    if item.get("status") not in {"ready_for_owner_review", "approval_required", "blocked_by_policy"}:
        raise ValueError(f"{label}: {item_label} status is invalid")


def _require_ids(
    items: list[dict[str, Any]],
    id_field: str,
    expected_ids: set[str],
    label: str,
    item_label: str,
) -> None:
    actual_ids = {str(item.get(id_field)) for item in items}
    if actual_ids != expected_ids:
        raise ValueError(f"{label}: {item_label} ids mismatch: expected={sorted(expected_ids)} actual={sorted(actual_ids)}")


def _require_count(items: list[dict[str, Any]], expected_count: int, label: str, item_label: str) -> None:
    if len(items) != expected_count:
        raise ValueError(f"{label}: expected {expected_count} {item_label}, got {len(items)}")


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


def _is_redacted_sha256(value: object) -> bool:
    return isinstance(value, str) and re.fullmatch(r"sha256:[0-9a-f]{64}", value) is not None
