"""FastAPI backend for ag2tracer web interface."""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, Response
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel

from . import core

app = FastAPI(title="ag2tracer", version="0.1.0")

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

# In-memory store for the currently uploaded trace
_current_trace: dict[str, Any] | None = None

# Frontend assets
_frontend_dir = Path(__file__).parent / "frontend"


# ---- API routes ----

class TraceInfo(BaseModel):
    num_steps: int
    agents: list[str]
    history: list[dict]


class AnalyzeRequest(BaseModel):
    method: str  # "all_at_once" | "step_by_step" | "binary_search"
    model: str = "gpt-4o"
    max_tokens: int = 1024


class AnalyzeResponse(BaseModel):
    agent_name: str
    step_number: int
    reason: str


@app.post("/api/upload", response_model=TraceInfo)
async def upload_trace(file: UploadFile = File(...)):
    """Upload a trace JSON file. Must contain a 'history' field."""
    global _current_trace

    content = await file.read()
    try:
        data = json.loads(content)
    except json.JSONDecodeError:
        raise HTTPException(status_code=400, detail="Invalid JSON file.")

    if "history" not in data or not isinstance(data["history"], list):
        raise HTTPException(status_code=400, detail="JSON must contain a 'history' array.")

    if len(data["history"]) == 0:
        raise HTTPException(status_code=400, detail="History array is empty.")

    _current_trace = data

    # Detect agent key and extract unique agents
    agent_key = core._detect_agent_key(data["history"])
    agents = list(dict.fromkeys(
        entry.get(agent_key, "Unknown") for entry in data["history"]
    ))

    return TraceInfo(
        num_steps=len(data["history"]),
        agents=agents,
        history=data["history"],
    )


@app.post("/api/analyze", response_model=AnalyzeResponse)
async def analyze_trace(req: AnalyzeRequest):
    """Run failure attribution on the uploaded trace."""
    if _current_trace is None:
        raise HTTPException(status_code=400, detail="No trace uploaded. Please upload a trace first.")

    methods = {
        "all_at_once": core.all_at_once,
        "step_by_step": core.step_by_step,
        "binary_search": core.binary_search,
    }

    if req.method not in methods:
        raise HTTPException(status_code=400, detail=f"Unknown method '{req.method}'. Choose from: {list(methods.keys())}")

    try:
        result = methods[req.method](
            trace=_current_trace,
            model=req.model,
            max_tokens=req.max_tokens,
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Attribution failed: {e}")

    return AnalyzeResponse(**result.to_dict())


# ---- Frontend serving ----

@app.get("/favicon.ico")
async def favicon():
    # Return an empty 1x1 pixel ICO to suppress browser 404s
    # 1x1 transparent ICO (minimal valid .ico)
    ico = (
        b'\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00 \x00'
        b'0\x00\x00\x00\x16\x00\x00\x00(\x00\x00\x00\x01\x00\x00'
        b'\x00\x02\x00\x00\x00\x01\x00 \x00\x00\x00\x00\x00\x04'
        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    )
    return Response(content=ico, media_type="image/x-icon")


@app.get("/")
async def root():
    return FileResponse(_frontend_dir / "index.html")


# Mount static assets if there are any beyond index.html
if _frontend_dir.exists():
    app.mount("/static", StaticFiles(directory=str(_frontend_dir)), name="static")
