"""Bernard dashboard API — FastAPI server serving alerts from Postgres."""
from __future__ import annotations

import json
import os
from contextlib import asynccontextmanager

import psycopg
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse

DB_DSN: str = ""


@asynccontextmanager
async def lifespan(app: FastAPI):
    global DB_DSN
    DB_DSN = os.environ["BERNARD_DB_DSN"]
    # Ensure tables exist
    conn = await psycopg.AsyncConnection.connect(DB_DSN)
    try:
        async with conn.cursor() as cur:
            await cur.execute("""
                CREATE TABLE IF NOT EXISTS bernard_alerts (
                    id SERIAL PRIMARY KEY,
                    alert_type TEXT NOT NULL,
                    title TEXT NOT NULL,
                    body TEXT NOT NULL,
                    metadata JSONB DEFAULT '{}',
                    created_at TIMESTAMPTZ DEFAULT NOW()
                )
            """)
            await cur.execute("""
                CREATE TABLE IF NOT EXISTS bernard_reviewed_prs (
                    id SERIAL PRIMARY KEY,
                    pr_key TEXT UNIQUE NOT NULL,
                    reviewed_at TIMESTAMPTZ DEFAULT NOW()
                )
            """)
        await conn.commit()
    finally:
        await conn.close()
    yield


app = FastAPI(title="Bernard Dashboard API", lifespan=lifespan)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/api/alerts")
async def get_alerts(limit: int = 50, alert_type: str | None = None):
    conn = await psycopg.AsyncConnection.connect(DB_DSN)
    try:
        async with conn.cursor() as cur:
            if alert_type:
                await cur.execute(
                    "SELECT id, alert_type, title, body, metadata, created_at FROM bernard_alerts WHERE alert_type=%s ORDER BY created_at DESC LIMIT %s",
                    (alert_type, limit),
                )
            else:
                await cur.execute(
                    "SELECT id, alert_type, title, body, metadata, created_at FROM bernard_alerts ORDER BY created_at DESC LIMIT %s",
                    (limit,),
                )
            rows = await cur.fetchall()
            return [
                {
                    "id": r[0],
                    "alert_type": r[1],
                    "title": r[2],
                    "body": r[3],
                    "metadata": r[4],
                    "created_at": r[5].isoformat() if r[5] else None,
                }
                for r in rows
            ]
    finally:
        await conn.close()


@app.get("/api/stats")
async def get_stats():
    conn = await psycopg.AsyncConnection.connect(DB_DSN)
    try:
        async with conn.cursor() as cur:
            await cur.execute("SELECT COUNT(*) FROM bernard_alerts")
            total = (await cur.fetchone())[0]
            await cur.execute("SELECT COUNT(*) FROM bernard_alerts WHERE alert_type='pr_review'")
            pr_reviews = (await cur.fetchone())[0]
            await cur.execute("SELECT COUNT(*) FROM bernard_alerts WHERE alert_type='workflow_failure'")
            wf_failures = (await cur.fetchone())[0]
            await cur.execute("SELECT COUNT(*) FROM bernard_reviewed_prs")
            reviewed_prs = (await cur.fetchone())[0]
            return {
                "total_alerts": total,
                "pr_reviews": pr_reviews,
                "workflow_failures": wf_failures,
                "reviewed_prs": reviewed_prs,
            }
    finally:
        await conn.close()


@app.get("/health")
async def health():
    return {"status": "ok", "agent": "bernard"}


@app.get("/{full_path:path}")
async def serve_spa(full_path: str):
    static_dir = os.path.join(os.path.dirname(__file__), "static")
    # If the user asks for a static file like JS/CSS, try to serve it directly
    file_path = os.path.join(static_dir, full_path)
    if os.path.isfile(file_path) and full_path:
        return FileResponse(file_path)
    # Otherwise return the SPA index.html
    return FileResponse(os.path.join(static_dir, "index.html"))
