"""AI Agent LOG post-write verifier dry-run.

Validates LOG feedback receipt candidates before a controlled KM / RAG /
PlayBook / MCP trust writeback lane is enabled. This module is deliberately
dry-run only: it performs structural verification against the committed
receipt plan and does not write KM, index RAG, update PlayBook trust, call MCP
tools, execute runtime actions, or persist raw log payloads.
"""

from __future__ import annotations

from typing import Any

from src.services.ai_agent_log_feedback_receipt_dry_run import (
    load_latest_ai_agent_log_feedback_receipt_dry_run,
)

_SCHEMA_VERSION = "ai_agent_log_post_write_verifier_dry_run_v1"
_SOURCE_READY_STATUS = "trusted_feedback_receipt_dry_run_ready"

_COMMON_REQUIRED_FIELDS = (
    "receipt_id",
    "target",
    "source_sample_id",
    "project_id",
    "product",
    "service",
    "package",
    "tool",
    "source_system",
    "redaction_state",
    "observed_event_count",
    "observed_field_count",
    "dry_run_status",
    "write_enabled",
    "raw_log_payload_persisted",
)

_TARGET_REQUIREMENTS: tuple[dict[str, Any], ...] = (
    {
        "target": "km",
        "node_id": "verify_km_memory_receipt_shape",
        "artifact": "km_memory_receipt_candidate",
        "required_fields": _COMMON_REQUIRED_FIELDS,
    },
    {
        "target": "rag",
        "node_id": "verify_rag_chunk_receipt_shape",
        "artifact": "rag_chunk_receipt_candidate",
        "required_fields": _COMMON_REQUIRED_FIELDS,
    },
    {
        "target": "playbook",
        "node_id": "verify_playbook_trust_receipt_shape",
        "artifact": "playbook_trust_receipt_candidate",
        "required_fields": _COMMON_REQUIRED_FIELDS,
    },
    {
        "target": "mcp",
        "node_id": "verify_mcp_audit_feedback_shape",
        "artifact": "mcp_audit_feedback_candidate",
        "required_fields": _COMMON_REQUIRED_FIELDS,
    },
    {
        "target": "verifier",
        "node_id": "verify_post_apply_feedback_binding",
        "artifact": "post_apply_verifier_feedback_receipt",
        "required_fields": _COMMON_REQUIRED_FIELDS,
    },
    {
        "target": "ai_agent",
        "node_id": "verify_agent_decision_context_binding",
        "artifact": "agent_decision_context_dry_run",
        "required_fields": _COMMON_REQUIRED_FIELDS,
    },
)

_SOURCE_FALSE_BOUNDARIES = (
    "km_write_performed",
    "rag_index_write_performed",
    "playbook_trust_write_performed",
    "mcp_tool_call_performed",
    "agent_runtime_action_performed",
    "post_apply_verifier_executed",
    "raw_log_payload_persisted",
    "secret_value_collection_allowed",
    "workflow_trigger_performed",
    "github_api_used",
)


def load_latest_ai_agent_log_post_write_verifier_dry_run() -> dict[str, Any]:
    """Return the latest dry-run verifier for LOG feedback receipt candidates."""
    source = load_latest_ai_agent_log_feedback_receipt_dry_run()
    source_rollups = source.get("rollups") or {}
    source_boundaries = source.get("operation_boundaries") or {}
    receipts = _candidate_receipts(source)
    source_ready = (
        source.get("status") == _SOURCE_READY_STATUS
        and source_rollups.get("dry_run_ready") is True
        and source.get("active_blockers") == []
    )
    target_verifications = [
        _verify_target(requirement, receipts) for requirement in _TARGET_REQUIREMENTS
    ]
    active_blockers = _active_blockers(
        source_ready=source_ready,
        source_boundaries=source_boundaries,
        receipts=receipts,
        target_verifications=target_verifications,
    )
    verifier_nodes = _verifier_nodes(
        source_ready=source_ready,
        target_verifications=target_verifications,
    )
    verified_candidate_count = sum(
        verification["verified_candidate_count"]
        for verification in target_verifications
    )

    return {
        "schema_version": _SCHEMA_VERSION,
        "priority": "P1-LOG-KM-RAG-MCP-PLAYBOOK",
        "scope": "ai_agent_log_post_write_verifier_dry_run",
        "status": (
            "post_write_verifier_dry_run_ready"
            if not active_blockers
            else "blocked_waiting_feedback_receipt_verifier"
        ),
        "readback": {
            "workplan_id": "P1-LOG-POST-WRITE-VERIFIER-DRY-RUN",
            "workplan_title": "KM / RAG / PlayBook / MCP feedback receipt post-write verifier dry-run",
            "source_schema_version": source.get("schema_version"),
            "source_status": source.get("status"),
            "safe_next_step": (
                "enable_controlled_km_rag_playbook_trust_writeback_with_post_write_verifier"
            ),
        },
        "verifier_nodes": verifier_nodes,
        "target_verifications": target_verifications,
        "rollups": {
            "verifier_node_count": len(verifier_nodes),
            "passed_verifier_node_count": sum(
                1 for node in verifier_nodes if node["status"] == "dry_run_passed"
            ),
            "target_count": len(_TARGET_REQUIREMENTS),
            "verified_target_count": sum(
                1
                for verification in target_verifications
                if verification["status"] == "target_receipts_verified"
            ),
            "candidate_receipt_count": len(receipts),
            "verified_candidate_receipt_count": verified_candidate_count,
            "source_pipeline_node_count": source_rollups.get("pipeline_node_count", 0),
            "source_candidate_receipt_count": source_rollups.get(
                "candidate_receipt_count",
                0,
            ),
            "runtime_sample_count": source_rollups.get("runtime_sample_count", 0),
            "dry_run_ready": not active_blockers,
            "controlled_writeback_next_step_ready": not active_blockers,
            "writeback_authorized_by_this_endpoint": False,
        },
        "active_blockers": active_blockers,
        "operation_boundaries": {
            "dry_run_only": True,
            "post_write_verifier_dry_run_performed": True,
            "km_write_performed": False,
            "rag_index_write_performed": False,
            "playbook_trust_write_performed": False,
            "mcp_tool_call_performed": False,
            "agent_runtime_action_performed": False,
            "post_write_verifier_runtime_write_performed": False,
            "raw_log_payload_persisted": False,
            "secret_value_collection_allowed": False,
            "workflow_trigger_performed": False,
            "github_api_used": False,
        },
    }


def _candidate_receipts(source: dict[str, Any]) -> list[dict[str, Any]]:
    receipts = source.get("candidate_receipts")
    if not isinstance(receipts, list):
        return []
    return [receipt for receipt in receipts if isinstance(receipt, dict)]


def _verify_target(
    requirement: dict[str, Any],
    receipts: list[dict[str, Any]],
) -> dict[str, Any]:
    target = requirement["target"]
    required_fields = tuple(requirement["required_fields"])
    target_receipts = [
        receipt for receipt in receipts if receipt.get("target") == target
    ]
    invalid_receipts = [
        _invalid_receipt(receipt, required_fields)
        for receipt in target_receipts
    ]
    invalid_receipts = [invalid for invalid in invalid_receipts if invalid["reasons"]]

    return {
        "target": target,
        "artifact": requirement["artifact"],
        "status": (
            "target_receipts_verified"
            if target_receipts and not invalid_receipts
            else "target_receipts_invalid_or_missing"
        ),
        "candidate_count": len(target_receipts),
        "verified_candidate_count": len(target_receipts) - len(invalid_receipts),
        "invalid_candidate_count": len(invalid_receipts),
        "required_fields": list(required_fields),
        "invalid_receipts": invalid_receipts,
        "write_enabled": False,
    }


def _invalid_receipt(
    receipt: dict[str, Any],
    required_fields: tuple[str, ...],
) -> dict[str, Any]:
    reasons: list[str] = []
    missing_fields = [
        field for field in required_fields if _missing_value(receipt.get(field))
    ]
    if missing_fields:
        reasons.append(f"missing_fields:{','.join(missing_fields)}")
    if receipt.get("dry_run_status") != "candidate_ready":
        reasons.append("dry_run_status_not_candidate_ready")
    if receipt.get("write_enabled") is not False:
        reasons.append("write_enabled_must_be_false")
    if receipt.get("raw_log_payload_persisted") is not False:
        reasons.append("raw_log_payload_must_not_be_persisted")
    if receipt.get("redaction_state") != "metadata_only_no_raw_payload":
        reasons.append("redaction_state_must_be_metadata_only")
    if not isinstance(receipt.get("observed_event_count"), int) or (
        receipt.get("observed_event_count") or 0
    ) <= 0:
        reasons.append("observed_event_count_must_be_positive")
    if not isinstance(receipt.get("observed_field_count"), int) or (
        receipt.get("observed_field_count") or 0
    ) <= 0:
        reasons.append("observed_field_count_must_be_positive")

    return {
        "receipt_id": str(receipt.get("receipt_id") or ""),
        "reasons": reasons,
    }


def _verifier_nodes(
    *,
    source_ready: bool,
    target_verifications: list[dict[str, Any]],
) -> list[dict[str, Any]]:
    verifications_by_target = {
        verification["target"]: verification for verification in target_verifications
    }
    nodes = []
    for requirement in _TARGET_REQUIREMENTS:
        verification = verifications_by_target.get(requirement["target"]) or {}
        target_ready = verification.get("status") == "target_receipts_verified"
        nodes.append(
            {
                "node_id": requirement["node_id"],
                "stage": "post_write_verifier_dry_run",
                "target": requirement["target"],
                "artifact": requirement["artifact"],
                "status": (
                    "dry_run_passed"
                    if source_ready and target_ready
                    else "blocked_waiting_valid_receipts"
                ),
                "write_enabled": False,
                "requires_controlled_writeback_verifier": True,
            }
        )
    return nodes


def _active_blockers(
    *,
    source_ready: bool,
    source_boundaries: dict[str, Any],
    receipts: list[dict[str, Any]],
    target_verifications: list[dict[str, Any]],
) -> list[str]:
    blockers: list[str] = []
    if not source_ready:
        blockers.append("feedback_receipt_dry_run_not_ready")
    if not receipts:
        blockers.append("candidate_receipts_missing")
    if source_boundaries.get("dry_run_only") is not True:
        blockers.append("source_boundary_dry_run_only_not_true")
    for boundary in _SOURCE_FALSE_BOUNDARIES:
        if source_boundaries.get(boundary) is not False:
            blockers.append(f"source_boundary_{boundary}_not_false")
    for verification in target_verifications:
        if verification["candidate_count"] == 0:
            blockers.append(f"{verification['target']}_candidate_receipts_missing")
        if verification["invalid_candidate_count"]:
            blockers.append(f"{verification['target']}_candidate_receipts_invalid")
    return _unique(blockers)


def _missing_value(value: Any) -> bool:
    if value is None:
        return True
    if isinstance(value, str) and not value.strip():
        return True
    return False


def _unique(values: list[str]) -> list[str]:
    seen = set()
    result = []
    for value in values:
        if value in seen:
            continue
        seen.add(value)
        result.append(value)
    return result
