import io
import json
import uuid

from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session

from app.api.deps import get_current_principal, get_project_or_404, require_role
from app.core.config import get_settings
from app.db.session import get_db
from app.models.dataset import Dataset
from app.models.org import User, UserRole
from app.models.stubs import EvaluationResult, EvaluationStatus
from app.schemas.evaluation import EvaluationResultOut, RunEvaluationRequest
from app.workers.evaluation_tasks import run_evaluation_task

router = APIRouter(prefix="/evaluation", tags=["evaluation"])
settings = get_settings()


@router.post("/run", status_code=202, response_model=EvaluationResultOut)
def run_evaluation(
    payload: RunEvaluationRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_role(UserRole.editor)),
):
    dataset = db.get(Dataset, payload.dataset_id)
    if dataset is None:
        raise HTTPException(status_code=404, detail="Dataset not found")
    get_project_or_404(dataset.project_id, db, current_user)

    evaluation = EvaluationResult(
        project_id=dataset.project_id,
        dataset_id=dataset.id,
        base_model=payload.base_model,
        status=EvaluationStatus.queued,
        created_by=current_user.id,
    )
    db.add(evaluation)
    db.commit()
    db.refresh(evaluation)

    run_evaluation_task.delay(
        str(evaluation.id),
        str(dataset.id),
        str(dataset.project_id),
        payload.base_model,
        payload.judge_model or settings.ollama_default_model,
        payload.use_rag,
        payload.sample_size,
    )
    return evaluation


@router.get("/results", response_model=list[EvaluationResultOut])
def list_results(
    project_id: uuid.UUID = Query(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_principal),
):
    get_project_or_404(project_id, db, current_user)
    return (
        db.query(EvaluationResult)
        .filter(EvaluationResult.project_id == project_id)
        .order_by(EvaluationResult.created_at.desc())
        .all()
    )


@router.get("/results/{evaluation_id}", response_model=EvaluationResultOut)
def get_result(
    evaluation_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(get_current_principal)
):
    evaluation = db.get(EvaluationResult, evaluation_id)
    if evaluation is None:
        raise HTTPException(status_code=404, detail="Evaluation not found")
    get_project_or_404(evaluation.project_id, db, current_user)
    return evaluation


@router.get("/results/{evaluation_id}/export")
def export_result(
    evaluation_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(get_current_principal)
):
    evaluation = db.get(EvaluationResult, evaluation_id)
    if evaluation is None:
        raise HTTPException(status_code=404, detail="Evaluation not found")
    get_project_or_404(evaluation.project_id, db, current_user)

    body = json.dumps(
        {
            "id": str(evaluation.id),
            "base_model": evaluation.base_model,
            "status": evaluation.status.value,
            "created_at": evaluation.created_at.isoformat(),
            "metrics": evaluation.metrics,
        },
        indent=2,
        ensure_ascii=False,
    )
    return StreamingResponse(
        io.BytesIO(body.encode("utf-8")),
        media_type="application/json",
        headers={"Content-Disposition": f"attachment; filename=evaluation-{evaluation.id}.json"},
    )
