"""FastAPI routes for sub-agent lifecycle tracking."""

from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Query

from peon_mcp.common.dependencies import get_db
from peon_mcp.common.schemas import PaginatedResponse
from peon_mcp.db import row_to_dict
from peon_mcp.subagents.schemas import (
    SubAgentLimitsResponse,
    SubAgentResponse,
    SubAgentSpawn,
    SubAgentUpdate,
)

router = APIRouter(tags=["SubAgents"])


def _compute_duration(row: dict) -> dict:
    """Add duration_seconds field based on started_at and ended_at."""
    from datetime import datetime

    started = row.get("started_at")
    ended = row.get("ended_at")
    if started and ended:
        try:
            fmt = "%Y-%m-%d %H:%M:%S"
            s = datetime.strptime(started, fmt)
            e = datetime.strptime(ended, fmt)
            row["duration_seconds"] = (e - s).total_seconds()
        except (ValueError, TypeError):
            row["duration_seconds"] = None
    else:
        row["duration_seconds"] = None
    return row


@router.get("/api/subagents/limits", response_model=SubAgentLimitsResponse)
async def check_subagent_limits(
    project_id: str = Query(...),
    db=Depends(get_db),
):
    """Check current sub-agent usage against project limits."""
    proj_rows = await db.execute_fetchall(
        "SELECT max_subagent_depth, max_subagents_per_task, max_concurrent_subagents FROM projects WHERE id = ?",
        (project_id,),
    )
    if not proj_rows:
        raise HTTPException(404, detail=f"No project found with id '{project_id}'")

    proj = row_to_dict(proj_rows[0])
    max_depth = proj["max_subagent_depth"]
    max_per_task = proj["max_subagents_per_task"]
    max_concurrent = proj["max_concurrent_subagents"]

    count_rows = await db.execute_fetchall(
        "SELECT status, COUNT(*) as cnt FROM sub_agents WHERE project_id = ? AND status IN ('running', 'pending') GROUP BY status",
        (project_id,),
    )
    current_running = 0
    current_pending = 0
    for r in count_rows:
        d = row_to_dict(r)
        if d["status"] == "running":
            current_running = d["cnt"]
        elif d["status"] == "pending":
            current_pending = d["cnt"]

    active = current_running + current_pending
    can_spawn = active < max_concurrent
    reason = "ok" if can_spawn else f"concurrency limit reached ({active}/{max_concurrent} active sub-agents)"

    return {
        "project_id": project_id,
        "max_subagent_depth": max_depth,
        "max_subagents_per_task": max_per_task,
        "max_concurrent_subagents": max_concurrent,
        "current_running": current_running,
        "current_pending": current_pending,
        "can_spawn": can_spawn,
        "reason": reason,
    }


@router.post("/api/subagents", response_model=SubAgentResponse, status_code=201)
async def spawn_subagent(body: SubAgentSpawn, db=Depends(get_db)):
    """Register a new sub-agent spawn, validating concurrency limits."""
    project_id = body.project_id.strip()

    # Validate project exists and get limits
    proj_rows = await db.execute_fetchall(
        "SELECT max_subagent_depth, max_subagents_per_task, max_concurrent_subagents FROM projects WHERE id = ?",
        (project_id,),
    )
    if not proj_rows:
        raise HTTPException(404, detail=f"No project found with id '{project_id}'")

    proj = row_to_dict(proj_rows[0])
    max_concurrent = proj["max_concurrent_subagents"]

    # Check idempotency: if key provided, return existing record
    if body.idempotency_key:
        existing = await db.execute_fetchall(
            "SELECT * FROM sub_agents WHERE idempotency_key = ? AND project_id = ?",
            (body.idempotency_key, project_id),
        )
        if existing:
            return _compute_duration(row_to_dict(existing[0]))

    # Check concurrency limit
    count_rows = await db.execute_fetchall(
        "SELECT COUNT(*) as cnt FROM sub_agents WHERE project_id = ? AND status IN ('running', 'pending')",
        (project_id,),
    )
    active = row_to_dict(count_rows[0])["cnt"] if count_rows else 0
    if active >= max_concurrent:
        raise HTTPException(
            429,
            detail=f"Concurrency limit reached: {active}/{max_concurrent} active sub-agents for project '{project_id}'",
        )

    cursor = await db.execute(
        """INSERT INTO sub_agents
           (parent_task_id, project_id, label, idempotency_key, model, timeout_seconds, status, depth)
           VALUES (?, ?, ?, ?, ?, ?, 'pending', 1)""",
        (
            body.parent_task_id,
            project_id,
            body.label,
            body.idempotency_key,
            body.model,
            body.timeout_seconds,
        ),
    )
    await db.commit()

    rows = await db.execute_fetchall(
        "SELECT * FROM sub_agents WHERE id = ?", (cursor.lastrowid,)
    )
    return _compute_duration(row_to_dict(rows[0]))


@router.get("/api/subagents", response_model=PaginatedResponse[SubAgentResponse])
async def list_subagents(
    project_id: str | None = Query(default=None),
    parent_task_id: int | None = Query(default=None),
    status: str | None = Query(default=None),
    limit: int = Query(default=50, ge=1, le=200),
    offset: int = Query(default=0, ge=0),
    db=Depends(get_db),
):
    """List sub-agents with optional filters."""
    conditions = []
    params: list = []

    if project_id is not None:
        conditions.append("project_id = ?")
        params.append(project_id)
    if parent_task_id is not None:
        conditions.append("parent_task_id = ?")
        params.append(parent_task_id)
    if status is not None:
        conditions.append("status = ?")
        params.append(status)

    where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
    count_rows = await db.execute_fetchall(
        f"SELECT COUNT(*) as cnt FROM sub_agents {where}", params
    )
    total = row_to_dict(count_rows[0])["cnt"] if count_rows else 0

    rows = await db.execute_fetchall(
        f"SELECT * FROM sub_agents {where} ORDER BY created_at DESC LIMIT ? OFFSET ?",
        params + [limit, offset],
    )
    items = [_compute_duration(row_to_dict(r)) for r in rows]

    return {
        "items": items,
        "total": total,
        "limit": limit,
        "offset": offset,
        "has_next": (offset + len(items)) < total,
    }


@router.get("/api/subagents/{subagent_id}", response_model=SubAgentResponse)
async def get_subagent(subagent_id: int, db=Depends(get_db)):
    """Get a sub-agent by ID."""
    rows = await db.execute_fetchall(
        "SELECT * FROM sub_agents WHERE id = ?", (subagent_id,)
    )
    if not rows:
        raise HTTPException(404, detail=f"No sub-agent found with id {subagent_id}")
    return _compute_duration(row_to_dict(rows[0]))


@router.put("/api/subagents/{subagent_id}", response_model=SubAgentResponse)
async def update_subagent(subagent_id: int, body: SubAgentUpdate, db=Depends(get_db)):
    """Update a sub-agent's status, result, or other fields."""
    rows = await db.execute_fetchall(
        "SELECT * FROM sub_agents WHERE id = ?", (subagent_id,)
    )
    if not rows:
        raise HTTPException(404, detail=f"No sub-agent found with id {subagent_id}")

    updates = []
    params: list = []

    if body.status is not None:
        updates.append("status = ?")
        params.append(body.status)
    if body.result_summary is not None:
        updates.append("result_summary = ?")
        params.append(body.result_summary)
    if body.tokens_used is not None:
        updates.append("tokens_used = ?")
        params.append(body.tokens_used)
    if body.ended_at is not None:
        updates.append("ended_at = ?")
        params.append(body.ended_at)
    if body.pid is not None:
        updates.append("pid = ?")
        params.append(body.pid)

    if updates:
        params.append(subagent_id)
        await db.execute(
            f"UPDATE sub_agents SET {', '.join(updates)} WHERE id = ?", params
        )
        await db.commit()

    rows = await db.execute_fetchall(
        "SELECT * FROM sub_agents WHERE id = ?", (subagent_id,)
    )
    return _compute_duration(row_to_dict(rows[0]))


@router.delete("/api/subagents/{subagent_id}", status_code=204)
async def delete_subagent(subagent_id: int, db=Depends(get_db)):
    """Remove a sub-agent record."""
    rows = await db.execute_fetchall(
        "SELECT 1 FROM sub_agents WHERE id = ?", (subagent_id,)
    )
    if not rows:
        raise HTTPException(404, detail=f"No sub-agent found with id {subagent_id}")

    await db.execute("DELETE FROM sub_agents WHERE id = ?", (subagent_id,))
    await db.commit()


@router.post("/api/subagents/{subagent_id}/kill", response_model=SubAgentResponse)
async def kill_subagent(subagent_id: int, db=Depends(get_db)):
    """Request timeout kill of a running sub-agent."""
    rows = await db.execute_fetchall(
        "SELECT * FROM sub_agents WHERE id = ?", (subagent_id,)
    )
    if not rows:
        raise HTTPException(404, detail=f"No sub-agent found with id {subagent_id}")

    agent = row_to_dict(rows[0])
    if agent["status"] not in ("pending", "running"):
        raise HTTPException(
            400,
            detail=f"Cannot kill sub-agent with status '{agent['status']}'. Only pending or running sub-agents can be killed.",
        )

    # Attempt OS-level kill if PID is known
    pid = agent.get("pid")
    if pid:
        import signal

        try:
            import os as _os
            _os.kill(pid, signal.SIGTERM)
        except (ProcessLookupError, PermissionError):
            pass  # Process already gone or not accessible

    await db.execute(
        "UPDATE sub_agents SET status = 'cancelled', ended_at = CURRENT_TIMESTAMP WHERE id = ?",
        (subagent_id,),
    )
    await db.commit()

    rows = await db.execute_fetchall(
        "SELECT * FROM sub_agents WHERE id = ?", (subagent_id,)
    )
    return _compute_duration(row_to_dict(rows[0]))
