"""Agent handoffs and collaboration matrix."""
from __future__ import annotations

import json
import uuid
from typing import Any, Optional

from app.db import execute, fetch_all, fetch_one
from app.services.agent_names import normalize_agent_key


def _serialize(row: dict[str, Any] | None) -> dict[str, Any] | None:
    if not row:
        return None
    out = dict(row)
    for k, v in list(out.items()):
        if hasattr(v, "isoformat"):
            out[k] = v.isoformat()
        elif k == "correlation_id" and v is not None:
            out[k] = str(v)
    return out


def list_collaboration() -> list[dict[str, Any]]:
    rows = fetch_all(
        "SELECT from_agent, to_agent, handoff_type, description FROM agent_collaboration ORDER BY from_agent, to_agent"
    )
    return [dict(r) for r in rows]


def create_handoff(
    from_agent: str,
    to_agent: str,
    *,
    handoff_type: str = "partner",
    payload: dict[str, Any] | None = None,
    correlation_id: str | None = None,
    status: str = "completed",
) -> dict[str, Any]:
    src = normalize_agent_key(from_agent)
    dst = normalize_agent_key(to_agent)
    if not src or not dst:
        raise ValueError("from_agent and to_agent required")
    cid = correlation_id or str(uuid.uuid4())
    try:
        uuid.UUID(str(cid))
    except ValueError:
        cid = str(uuid.uuid4())
    row = fetch_one(
        """
        INSERT INTO agent_handoffs (correlation_id, from_agent, to_agent, handoff_type, payload, status, completed_at)
        VALUES (%s::uuid, %s, %s, %s, %s::jsonb, %s, CASE WHEN %s = 'completed' THEN NOW() ELSE NULL END)
        RETURNING *
        """,
        (cid, src, dst, handoff_type, json.dumps(payload or {}), status, status),
    )
    handoff = _serialize(row) or {}
    meta = {
        "correlation_id": cid,
        "handoff_id": handoff.get("id"),
        "target_agent": dst,
        "source_agent": src,
        "handoff_type": handoff_type,
    }
    _log_handoff_events(src, dst, handoff_type, payload or {}, meta, cid)
    return handoff


def _log_handoff_events(
    src: str,
    dst: str,
    handoff_type: str,
    payload: dict[str, Any],
    meta: dict[str, Any],
    cid: str,
) -> None:
    title_out = f"{src} → {dst}: {handoff_type}"
    title_in = f"Handoff van {src}: {handoff_type}"
    body = json.dumps(payload)[:2000] if payload else ""
    for agent, etype, title, extra in (
        (src, "handoff_out", title_out, {"target_agent": dst}),
        (dst, "handoff_in", title_in, {"source_agent": src}),
    ):
        try:
            execute(
                """
                INSERT INTO agent_events (agent_name, agent_type, event_type, title, body, status, channel, metadata)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s::jsonb)
                """,
                (
                    agent,
                    "agent_handoff",
                    etype,
                    title[:255],
                    body,
                    "completed",
                    "agents",
                    json.dumps({**meta, **extra}),
                ),
            )
        except Exception:
            pass


def recent_handoffs(hours: int = 6) -> list[dict[str, Any]]:
    rows = fetch_all(
        """
        SELECT * FROM agent_handoffs
        WHERE created_at >= NOW() - make_interval(hours => %s)
        ORDER BY created_at DESC
        LIMIT 200
        """,
        (max(1, min(hours, 168)),),
    )
    return [_serialize(r) for r in rows if r]


def peer_edges_live(hours: int = 6) -> list[dict[str, Any]]:
    rows = fetch_all(
        """
        SELECT from_agent, to_agent, handoff_type, COUNT(*) AS weight,
               MAX(correlation_id::text) AS correlation_id
        FROM agent_handoffs
        WHERE created_at >= NOW() - make_interval(hours => %s)
          AND status = 'completed'
        GROUP BY from_agent, to_agent, handoff_type
        """,
        (max(1, min(hours, 168)),),
    )
    return [
        {
            "source": str(r["from_agent"]),
            "target": str(r["to_agent"]),
            "type": "live",
            "handoff_type": r.get("handoff_type"),
            "weight": int(r["weight"] or 1),
            "correlation_id": r.get("correlation_id"),
        }
        for r in rows
    ]
