"""Loop directive REST API routes."""

from __future__ import annotations

import json
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query

from peon_mcp.common.dependencies import get_db
from peon_mcp.directives.schemas import (
    DirectiveCreate,
    DirectiveResponse,
    DirectiveStatus,
    DirectiveUpdate,
)

router = APIRouter(tags=["Loop Directives"])


@router.get("/api/loops/{loop_id}/directives", response_model=list[DirectiveResponse])
async def list_directives(
    loop_id: str,
    status: DirectiveStatus | None = Query(default=DirectiveStatus.pending),
    db=Depends(get_db),
):
    """List directives for a loop, filterable by status. Defaults to pending only."""
    params: list = [loop_id]
    where = "WHERE loop_id = ?"
    if status is not None:
        where += " AND status = ?"
        params.append(status.value)

    rows = await db.execute_fetchall(
        f"SELECT * FROM loop_directives {where} ORDER BY created_at ASC",
        params,
    )
    return [_fix_jsonb(dict(r)) for r in rows]


@router.post("/api/loops/{loop_id}/directives", response_model=DirectiveResponse, status_code=201)
async def create_directive(
    loop_id: str,
    body: DirectiveCreate,
    db=Depends(get_db),
):
    """Create a new directive for a loop."""
    rows = await db.execute_fetchall(
        "INSERT INTO loop_directives (loop_id, directive_type, payload, created_by)"
        " VALUES (?, ?, ?::jsonb, ?)"
        " RETURNING *",
        (loop_id, body.directive_type.value, _json_str(body.payload), body.created_by),
    )
    await db.commit()
    return _fix_jsonb(dict(rows[0]))


@router.patch("/api/directives/{directive_id}", response_model=DirectiveResponse)
async def update_directive(
    directive_id: UUID,
    body: DirectiveUpdate,
    db=Depends(get_db),
):
    """Update a directive's status. Sets acknowledged_at when status becomes acknowledged."""
    # Fetch existing
    rows = await db.execute_fetchall(
        "SELECT * FROM loop_directives WHERE id = ?",
        (str(directive_id),),
    )
    if not rows:
        raise HTTPException(404, detail=f"Directive {directive_id} not found")

    ack_clause = ""
    if body.status == DirectiveStatus.acknowledged:
        ack_clause = ", acknowledged_at = CURRENT_TIMESTAMP"

    rows = await db.execute_fetchall(
        f"UPDATE loop_directives SET status = ?{ack_clause} WHERE id = ? RETURNING *",
        (body.status.value, str(directive_id)),
    )
    await db.commit()
    return _fix_jsonb(dict(rows[0]))


def _json_str(data: dict) -> str:
    """Serialize dict to JSON string for JSONB parameter."""
    return json.dumps(data)


def _fix_jsonb(row: dict) -> dict:
    """Ensure JSONB fields are dicts, not strings."""
    if isinstance(row.get("payload"), str):
        try:
            row["payload"] = json.loads(row["payload"])
        except (json.JSONDecodeError, TypeError):
            row["payload"] = {}
    return row
