"""AI Agent LOG controlled writeback dispatch.

Records metadata-only controlled dispatch receipts for LOG feedback batches.
This route writes only to the internal automation operation ledger; it does
not write KM/RAG/PlayBook state, call MCP tools, trigger workflows, send
Telegram messages, persist raw log payloads, or read secrets.
"""

from __future__ import annotations

import json
from typing import Any

from sqlalchemy import text

from src.db.base import get_db_context
from src.services.ai_agent_log_controlled_writeback_executor_readback import (
    load_latest_ai_agent_log_controlled_writeback_executor_readback,
)

SCHEMA_VERSION = "ai_agent_log_controlled_writeback_dispatch_receipt_v1"
OPERATION_TYPE = "log_controlled_writeback_dispatched"
FALLBACK_LEDGER_OPERATION_TYPE = "km_linked"
EXECUTOR_ROUTE = "ai_agent_metadata_writeback_executor"
DEFAULT_PROJECT_ID = "awoooi"


async def dispatch_latest_ai_agent_log_controlled_writeback(
    *,
    project_id: str = DEFAULT_PROJECT_ID,
) -> dict[str, Any]:
    """Persist idempotent metadata-only dispatch receipts for ready LOG batches."""

    executor = load_latest_ai_agent_log_controlled_writeback_executor_readback()
    receipt = build_ai_agent_log_controlled_writeback_dispatch_receipt(executor)
    if receipt["active_blockers"]:
        return receipt

    rows = []
    async with get_db_context(project_id) as db:
        ledger_operation_type = await _resolve_ledger_operation_type(db)
        for batch in receipt["dispatch_batches"]:
            inserted = await _insert_dispatch_row(
                db,
                project_id=project_id,
                batch=batch,
                ledger_operation_type=ledger_operation_type,
            )
            rows.append(inserted)

    inserted_count = sum(1 for row in rows if row["created"] is True)
    existing_count = sum(1 for row in rows if row["created"] is False)
    receipt["dispatch_result"] = {
        "operation_type": OPERATION_TYPE,
        "ledger_operation_type": ledger_operation_type,
        "semantic_operation_type": OPERATION_TYPE,
        "inserted_count": inserted_count,
        "existing_count": existing_count,
        "ledger_row_count": len(rows),
        "rows": rows,
    }
    receipt["rollups"]["runtime_dispatch_performed"] = True
    receipt["rollups"]["dispatch_ledger_row_count"] = len(rows)
    receipt["rollups"]["inserted_dispatch_ledger_row_count"] = inserted_count
    receipt["rollups"]["existing_dispatch_ledger_row_count"] = existing_count
    receipt["operation_boundaries"]["executor_dispatch_performed"] = True
    return receipt


def build_ai_agent_log_controlled_writeback_dispatch_receipt(
    executor: dict[str, Any] | None = None,
) -> dict[str, Any]:
    """Build the deterministic dispatch receipt envelope from executor readback."""

    source = executor or load_latest_ai_agent_log_controlled_writeback_executor_readback()
    batches = [
        batch
        for batch in source.get("execution_batches", [])
        if isinstance(batch, dict)
    ]
    dispatch_batches = [_dispatch_batch(batch) for batch in batches]
    active_blockers = _active_blockers(source=source, dispatch_batches=dispatch_batches)
    return {
        "schema_version": SCHEMA_VERSION,
        "priority": "P1-LOG-KM-RAG-MCP-PLAYBOOK",
        "scope": "ai_agent_log_controlled_writeback_dispatch",
        "status": (
            "controlled_writeback_dispatch_ready"
            if not active_blockers
            else "blocked_waiting_controlled_writeback_dispatch_inputs"
        ),
        "readback": {
            "workplan_id": "P1-LOG-CONTROLLED-WRITEBACK-DISPATCH",
            "workplan_title": "LOG feedback metadata-only controlled dispatch receipt",
            "source_schema_version": source.get("schema_version"),
            "source_status": source.get("status"),
            "executor_route": EXECUTOR_ROUTE,
            "operation_type": OPERATION_TYPE,
            "safe_next_step": "post_apply_verify_dispatch_receipts_then_consume_learning_targets",
        },
        "dispatch_batches": dispatch_batches,
        "rollups": {
            "source_execution_batch_count": len(batches),
            "ready_source_execution_batch_count": sum(
                1
                for batch in batches
                if batch.get("status") == "ready_for_controlled_executor_dispatch"
            ),
            "dispatch_batch_count": len(dispatch_batches),
            "ready_dispatch_batch_count": sum(
                1 for batch in dispatch_batches if batch["status"] == "ready_for_ledger_write"
            ),
            "target_selector_count": sum(
                batch["target_selector_count"] for batch in dispatch_batches
            ),
            "source_of_truth_diff_count": sum(
                batch["source_of_truth_diff_count"] for batch in dispatch_batches
            ),
            "post_apply_verifier_ref_count": sum(
                batch["post_apply_verifier_ref_count"] for batch in dispatch_batches
            ),
            "controlled_ledger_write_ready": not active_blockers,
            "runtime_dispatch_performed": False,
            "dispatch_ledger_row_count": 0,
            "inserted_dispatch_ledger_row_count": 0,
            "existing_dispatch_ledger_row_count": 0,
        },
        "active_blockers": active_blockers,
        "operation_boundaries": {
            "metadata_ledger_write_only": True,
            "executor_dispatch_performed": False,
            "km_write_performed": False,
            "rag_index_write_performed": False,
            "playbook_trust_write_performed": False,
            "mcp_tool_call_performed": False,
            "agent_runtime_action_performed": False,
            "telegram_send_performed": False,
            "workflow_trigger_performed": False,
            "raw_log_payload_persisted": False,
            "secret_value_collection_allowed": False,
            "github_api_used": False,
        },
    }


def _dispatch_batch(batch: dict[str, Any]) -> dict[str, Any]:
    verifier_refs = (batch.get("post_apply_verifier") or {}).get("verifier_refs")
    if not isinstance(verifier_refs, list):
        verifier_refs = []
    return {
        "dispatch_receipt_id": f"{OPERATION_TYPE}::{batch.get('target')}",
        "batch_id": str(batch.get("batch_id") or ""),
        "target": str(batch.get("target") or ""),
        "target_surface": str(batch.get("target_surface") or ""),
        "risk_tier": str(batch.get("risk_tier") or ""),
        "executor_route": str(batch.get("executor_route") or ""),
        "status": (
            "ready_for_ledger_write"
            if _batch_ready_for_dispatch(batch)
            else "blocked_waiting_batch_controls"
        ),
        "plan_count": int(batch.get("plan_count") or 0),
        "plan_ids": _strings(batch.get("plan_ids")),
        "receipt_ids": _strings(batch.get("receipt_ids")),
        "target_selector_count": int(batch.get("target_selector_count") or 0),
        "source_of_truth_diff_count": int(batch.get("source_of_truth_diff_count") or 0),
        "post_apply_verifier_ref_count": len(verifier_refs),
        "post_apply_verifier_refs": [str(ref) for ref in verifier_refs],
        "check_mode_verified": (batch.get("check_mode") or {}).get("enabled") is True,
        "rollback_ready": (batch.get("rollback") or {}).get("required") is True,
        "raw_payload_included": any(
            (diff or {}).get("raw_payload_included") is not False
            for diff in batch.get("source_of_truth_diffs") or []
        ),
    }


def _batch_ready_for_dispatch(batch: dict[str, Any]) -> bool:
    if batch.get("status") != "ready_for_controlled_executor_dispatch":
        return False
    if batch.get("dispatch_enabled_by_policy") is not True:
        return False
    if batch.get("executor_route") != EXECUTOR_ROUTE:
        return False
    if (batch.get("check_mode") or {}).get("enabled") is not True:
        return False
    if (batch.get("rollback") or {}).get("required") is not True:
        return False
    if (batch.get("post_apply_verifier") or {}).get("required") is not True:
        return False
    if int(batch.get("target_selector_count") or 0) <= 0:
        return False
    if int(batch.get("source_of_truth_diff_count") or 0) <= 0:
        return False
    for diff in batch.get("source_of_truth_diffs") or []:
        if not isinstance(diff, dict):
            return False
        if diff.get("raw_payload_included") is not False:
            return False
    return True


def _active_blockers(
    *,
    source: dict[str, Any],
    dispatch_batches: list[dict[str, Any]],
) -> list[str]:
    blockers = []
    if source.get("status") != "controlled_writeback_executor_ready":
        blockers.append("controlled_writeback_executor_not_ready")
    if (source.get("rollups") or {}).get("controlled_executor_dispatch_ready") is not True:
        blockers.append("controlled_executor_dispatch_not_ready")
    if not dispatch_batches:
        blockers.append("dispatch_batches_missing")
    for batch in dispatch_batches:
        target = batch["target"] or "unknown"
        if batch["status"] != "ready_for_ledger_write":
            blockers.append(f"{target}_dispatch_batch_not_ready")
        if batch["raw_payload_included"] is not False:
            blockers.append(f"{target}_raw_payload_included")
    return _unique(blockers)


async def _insert_dispatch_row(
    db: Any,
    *,
    project_id: str,
    batch: dict[str, Any],
    ledger_operation_type: str,
) -> dict[str, Any]:
    result = await db.execute(
        text("""
            INSERT INTO automation_operation_log (
                operation_type, actor, status,
                input, output, dry_run_result, tags
            )
            SELECT
                :ledger_operation_type,
                :actor,
                'success',
                CAST(:input AS jsonb),
                CAST(:output AS jsonb),
                CAST(:dry_run_result AS jsonb),
                :tags
            WHERE NOT EXISTS (
                SELECT 1
                FROM automation_operation_log existing
                WHERE coalesce(
                    existing.input ->> 'semantic_operation_type',
                    existing.operation_type
                ) = :operation_type
                  AND existing.input ->> 'dispatch_receipt_id' = :dispatch_receipt_id
            )
            RETURNING op_id::text
        """),
        {
            "operation_type": OPERATION_TYPE,
            "ledger_operation_type": ledger_operation_type,
            "actor": EXECUTOR_ROUTE,
            "dispatch_receipt_id": batch["dispatch_receipt_id"],
            "input": json.dumps(
                {
                    "schema_version": SCHEMA_VERSION,
                    "project_id": project_id,
                    "semantic_operation_type": OPERATION_TYPE,
                    "ledger_operation_type": ledger_operation_type,
                    "dispatch_receipt_id": batch["dispatch_receipt_id"],
                    "batch_id": batch["batch_id"],
                    "target": batch["target"],
                    "target_surface": batch["target_surface"],
                    "risk_tier": batch["risk_tier"],
                    "plan_ids": batch["plan_ids"],
                    "receipt_ids": batch["receipt_ids"],
                    "raw_payload_included": False,
                },
                ensure_ascii=False,
            ),
            "output": json.dumps(
                {
                    "executor_route": EXECUTOR_ROUTE,
                    "semantic_operation_type": OPERATION_TYPE,
                    "ledger_operation_type": ledger_operation_type,
                    "ledger_receipt_recorded": True,
                    "post_apply_verifier_refs": batch["post_apply_verifier_refs"],
                    "next_action": "consume_metadata_receipt_in_km_rag_playbook_agent_context",
                    "km_write_performed": False,
                    "rag_index_write_performed": False,
                    "playbook_trust_write_performed": False,
                    "mcp_tool_call_performed": False,
                    "telegram_send_performed": False,
                },
                ensure_ascii=False,
            ),
            "dry_run_result": json.dumps(
                {
                    "target_selector_count": batch["target_selector_count"],
                    "source_of_truth_diff_count": batch["source_of_truth_diff_count"],
                    "check_mode_verified": batch["check_mode_verified"],
                    "rollback_ready": batch["rollback_ready"],
                    "post_apply_verifier_ref_count": batch["post_apply_verifier_ref_count"],
                    "raw_payload_included": False,
                },
                ensure_ascii=False,
            ),
            "tags": [
                "ai_agent",
                "log_feedback",
                "controlled_writeback",
                batch["target"],
            ],
        },
    )
    op_id = result.scalar()
    if op_id:
        return {
            "dispatch_receipt_id": batch["dispatch_receipt_id"],
            "target": batch["target"],
            "created": True,
            "op_id": str(op_id),
        }

    existing = await db.execute(
        text("""
            SELECT op_id::text
            FROM automation_operation_log
            WHERE coalesce(input ->> 'semantic_operation_type', operation_type) = :operation_type
              AND input ->> 'dispatch_receipt_id' = :dispatch_receipt_id
            ORDER BY created_at DESC
            LIMIT 1
        """),
        {
            "operation_type": OPERATION_TYPE,
            "dispatch_receipt_id": batch["dispatch_receipt_id"],
        },
    )
    return {
        "dispatch_receipt_id": batch["dispatch_receipt_id"],
        "target": batch["target"],
        "created": False,
        "op_id": str(existing.scalar() or ""),
    }


async def _resolve_ledger_operation_type(db: Any) -> str:
    result = await db.execute(
        text("""
            SELECT CASE
                WHEN EXISTS (
                    SELECT 1
                    FROM pg_constraint
                    WHERE conname = 'automation_operation_log_type_valid'
                      AND pg_get_constraintdef(oid) LIKE '%' || :operation_type || '%'
                )
                THEN :operation_type
                ELSE :fallback_operation_type
            END
        """),
        {
            "operation_type": OPERATION_TYPE,
            "fallback_operation_type": FALLBACK_LEDGER_OPERATION_TYPE,
        },
    )
    resolved = str(result.scalar() or "")
    if resolved == OPERATION_TYPE:
        return OPERATION_TYPE
    return FALLBACK_LEDGER_OPERATION_TYPE


def _strings(value: Any) -> list[str]:
    if not isinstance(value, list):
        return []
    return [str(item) for item in value]


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
