from __future__ import annotations

from pathlib import Path

from fastapi import APIRouter, Depends, Form, HTTPException, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session

from evalkit.server.comparison import build_comparison, eval_to_comparison_dict
from evalkit.server.db.models import EvaluationModel, EvaluationStatus, ProjectModel
from evalkit.server.db.session import get_db

router = APIRouter()
templates = Jinja2Templates(directory=str(Path(__file__).parent.parent / "templates"))


PER_PAGE = 10


@router.get("/projects/{project_id}", response_class=HTMLResponse)
def project_detail(project_id: int, request: Request, page: int = 1, db: Session = Depends(get_db)):
    project = db.get(ProjectModel, project_id)
    if project is None:
        raise HTTPException(status_code=404, detail="Project not found")

    if page < 1:
        page = 1

    total = db.query(EvaluationModel).filter(EvaluationModel.project_id == project_id).count()
    total_pages = max(1, (total + PER_PAGE - 1) // PER_PAGE)
    if page > total_pages:
        page = total_pages

    evaluations = (
        db.query(EvaluationModel)
        .filter(EvaluationModel.project_id == project_id)
        .order_by(EvaluationModel.created_at.desc())
        .offset((page - 1) * PER_PAGE)
        .limit(PER_PAGE)
        .all()
    )

    # Chart needs all completed evaluations across all pages
    all_completed = (
        db.query(EvaluationModel)
        .filter(
            EvaluationModel.project_id == project_id,
            EvaluationModel.status == EvaluationStatus.complete,
            EvaluationModel.average_score.isnot(None),
        )
        .order_by(EvaluationModel.created_at.asc())
        .all()
    )

    return templates.TemplateResponse(
        request,
        "project.html",
        {
            "project": project,
            "evaluations": evaluations,
            "completed": all_completed,
            "page": page,
            "total_pages": total_pages,
            "total": total,
        },
    )


@router.post("/projects", response_class=HTMLResponse, status_code=201)
def create_project(
    request: Request,
    name: str = Form(...),
    description: str = Form(""),
    db: Session = Depends(get_db),
):
    existing = db.query(ProjectModel).filter(ProjectModel.name == name).first()
    if existing:
        raise HTTPException(status_code=409, detail=f"Project '{name}' already exists")
    project = ProjectModel(name=name, description=description)
    db.add(project)
    db.commit()
    db.refresh(project)
    return RedirectResponse(url=f"/projects/{project.id}", status_code=303)


@router.get("/projects/{project_id}/compare", response_class=HTMLResponse)
def compare_evaluations(
    project_id: int, ids: str, request: Request, baseline: int | None = None, db: Session = Depends(get_db)
):
    project = db.get(ProjectModel, project_id)
    if project is None:
        raise HTTPException(status_code=404, detail="Project not found")

    try:
        eval_ids = [int(x.strip()) for x in ids.split(",")]
    except ValueError:
        raise HTTPException(status_code=400, detail="ids must be comma-separated integers")

    if len(eval_ids) < 2:
        raise HTTPException(status_code=400, detail="At least 2 evaluation IDs required")

    evaluations = []
    for eid in eval_ids:
        ev = db.get(EvaluationModel, eid)
        if ev is None:
            raise HTTPException(status_code=404, detail=f"Evaluation {eid} not found")
        if ev.project_id != project_id:
            raise HTTPException(status_code=422)
        if ev.status != EvaluationStatus.complete:
            raise HTTPException(status_code=422)
        evaluations.append(ev)

    if baseline is None:
        evaluations.sort(key=lambda e: e.id)
        baseline = evaluations[0].id
    elif baseline not in eval_ids:
        raise HTTPException(status_code=400, detail="baseline must be one of the provided ids")

    baseline_ev = next(e for e in evaluations if e.id == baseline)
    comparison_evs = [e for e in evaluations if e.id != baseline]

    comparison = build_comparison(
        eval_to_comparison_dict(baseline_ev),
        [eval_to_comparison_dict(e) for e in comparison_evs],
    )

    return templates.TemplateResponse(
        request,
        "compare.html",
        {
            "project": project,
            "comparison": comparison,
        },
    )
