"""Webhook REST API routes."""

import json

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.webhooks.schemas import (
    EventLogResponse,
    WebhookConfigCreate,
    WebhookConfigResponse,
    WebhookConfigUpdate,
)

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


def _row_to_webhook(row) -> dict:
    """Convert a webhook_configs row to a dict with events parsed from JSON."""
    d = row_to_dict(row)
    if isinstance(d.get("events"), str):
        try:
            d["events"] = json.loads(d["events"])
        except (json.JSONDecodeError, TypeError):
            d["events"] = []
    d["enabled"] = bool(d.get("enabled", 1))
    return d


@router.post("/api/webhooks", response_model=WebhookConfigResponse, status_code=201)
async def create_webhook(body: WebhookConfigCreate, db=Depends(get_db)):
    """Create a webhook configuration for a project."""
    name = body.name.strip()
    url = body.url.strip()
    if not name or not url:
        raise HTTPException(400, detail="name and url are required")

    events_json = json.dumps(body.events)
    cursor = await db.execute(
        """INSERT INTO webhook_configs (project_id, name, url, secret, events, enabled)
           VALUES (?, ?, ?, ?, ?, ?)""",
        (body.project_id, name, url, body.secret, events_json, 1 if body.enabled else 0),
    )
    await db.commit()
    rows = await db.execute_fetchall(
        "SELECT * FROM webhook_configs WHERE id = ?", (cursor.lastrowid,)
    )
    return _row_to_webhook(rows[0])


@router.get("/api/webhooks", response_model=PaginatedResponse[WebhookConfigResponse])
async def list_webhooks(
    project_id: str = Query(...),
    limit: int = Query(default=50, ge=1, le=200),
    offset: int = Query(default=0, ge=0),
    db=Depends(get_db),
):
    """List webhook configurations for a project."""
    count_rows = await db.execute_fetchall(
        "SELECT COUNT(*) FROM webhook_configs WHERE project_id = ?",
        (project_id,),
    )
    total = count_rows[0][0] if count_rows else 0

    rows = await db.execute_fetchall(
        "SELECT * FROM webhook_configs WHERE project_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?",
        (project_id, limit, offset),
    )
    items = [_row_to_webhook(r) for r in rows]

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


@router.get("/api/webhooks/{webhook_id}", response_model=WebhookConfigResponse)
async def get_webhook(webhook_id: int, db=Depends(get_db)):
    """Get a single webhook configuration."""
    rows = await db.execute_fetchall(
        "SELECT * FROM webhook_configs WHERE id = ?", (webhook_id,)
    )
    if not rows:
        raise HTTPException(404, detail="Webhook not found")
    return _row_to_webhook(rows[0])


@router.put("/api/webhooks/{webhook_id}", response_model=WebhookConfigResponse)
async def update_webhook(webhook_id: int, body: WebhookConfigUpdate, db=Depends(get_db)):
    """Update a webhook configuration."""
    rows = await db.execute_fetchall(
        "SELECT * FROM webhook_configs WHERE id = ?", (webhook_id,)
    )
    if not rows:
        raise HTTPException(404, detail="Webhook not found")

    updates = {}
    if body.name is not None:
        updates["name"] = body.name.strip()
    if body.url is not None:
        updates["url"] = body.url.strip()
    if body.secret is not None:
        updates["secret"] = body.secret
    if body.events is not None:
        updates["events"] = json.dumps(body.events)
    if body.enabled is not None:
        updates["enabled"] = 1 if body.enabled else 0

    if updates:
        set_clause = ", ".join(f"{k} = ?" for k in updates)
        values = list(updates.values()) + [webhook_id]
        await db.execute(
            f"UPDATE webhook_configs SET {set_clause}, updated_at = CURRENT_TIMESTAMP WHERE id = ?",
            values,
        )
        await db.commit()

    rows = await db.execute_fetchall(
        "SELECT * FROM webhook_configs WHERE id = ?", (webhook_id,)
    )
    return _row_to_webhook(rows[0])


@router.delete("/api/webhooks/{webhook_id}", status_code=204)
async def delete_webhook(webhook_id: int, db=Depends(get_db)):
    """Delete a webhook configuration."""
    rows = await db.execute_fetchall(
        "SELECT id FROM webhook_configs WHERE id = ?", (webhook_id,)
    )
    if not rows:
        raise HTTPException(404, detail="Webhook not found")

    await db.execute("DELETE FROM webhook_configs WHERE id = ?", (webhook_id,))
    await db.commit()


@router.get("/api/webhooks/{webhook_id}/events", response_model=PaginatedResponse[EventLogResponse])
async def list_webhook_events(
    webhook_id: int,
    limit: int = Query(default=50, ge=1, le=200),
    offset: int = Query(default=0, ge=0),
    db=Depends(get_db),
):
    """List event log entries for a webhook configuration."""
    rows = await db.execute_fetchall(
        "SELECT id FROM webhook_configs WHERE id = ?", (webhook_id,)
    )
    if not rows:
        raise HTTPException(404, detail="Webhook not found")

    count_rows = await db.execute_fetchall(
        "SELECT COUNT(*) FROM webhook_event_logs WHERE webhook_config_id = ?",
        (webhook_id,),
    )
    total = count_rows[0][0] if count_rows else 0

    rows = await db.execute_fetchall(
        """SELECT * FROM webhook_event_logs WHERE webhook_config_id = ?
           ORDER BY created_at DESC LIMIT ? OFFSET ?""",
        (webhook_id, limit, offset),
    )
    items = [row_to_dict(r) for r in rows]

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


@router.post("/api/webhooks/{webhook_id}/test", response_model=EventLogResponse, status_code=201)
async def test_webhook(webhook_id: int, db=Depends(get_db)):
    """Send a test event to verify the webhook configuration works."""
    rows = await db.execute_fetchall(
        "SELECT * FROM webhook_configs WHERE id = ?", (webhook_id,)
    )
    if not rows:
        raise HTTPException(404, detail="Webhook not found")

    webhook = _row_to_webhook(rows[0])
    project_id = webhook["project_id"]
    test_payload = json.dumps({"event": "test", "message": "Peon test event — zug zug!"})

    status = "pending"
    response_code = None
    error = ""

    try:
        import httpx
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.post(
                webhook["url"],
                content=test_payload,
                headers={"Content-Type": "application/json", "X-Peon-Event": "test"},
            )
            response_code = response.status_code
            status = "success" if response.is_success else "failed"
    except Exception as exc:
        status = "failed"
        error = str(exc)

    cursor = await db.execute(
        """INSERT INTO webhook_event_logs
           (project_id, webhook_config_id, event_type, payload, status, response_code, error)
           VALUES (?, ?, ?, ?, ?, ?, ?)""",
        (project_id, webhook_id, "test", test_payload, status, response_code, error),
    )
    await db.commit()

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