from __future__ import annotations

from fastapi import FastAPI, HTTPException
from fastapi.middleware.gzip import GZipMiddleware
from pydantic import BaseModel

from .cluster_service import ClusteringServiceError, cluster_embeddings, cluster_run
from .models import (
    ClusteringAlgorithm,
    PythonClusteringRequest,
    PythonClusteringResponse,
    PythonRunExecutionRequest,
    ReductionMethod,
)
from .run_db_loader import load_run_and_embeddings


app = FastAPI(
    title="DIP Clustering Service",
    version="2.0.0",
    description="Remote clustering backend for DIP embedding clustering runs.",
)
app.add_middleware(GZipMiddleware, minimum_size=1024)


class HealthResponse(BaseModel):
    status: str
    algorithms: list[str]
    reductionMethods: list[str]
    endpoints: list[str]


@app.get("/health", response_model=HealthResponse)
def health() -> HealthResponse:
    return HealthResponse(
        status="UP",
        algorithms=[algorithm.value for algorithm in ClusteringAlgorithm],
        reductionMethods=[method.value for method in ReductionMethod],
        endpoints=["/cluster", "/cluster-run"],
    )


@app.post("/cluster", response_model=PythonClusteringResponse)
def cluster_direct(request: PythonClusteringRequest) -> PythonClusteringResponse:
    try:
        return cluster_embeddings(request)
    except ClusteringServiceError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    except Exception as exc:  # pragma: no cover - last-resort guard
        raise HTTPException(status_code=500, detail=f"Unexpected clustering failure: {exc}") from exc


@app.post("/cluster-run", response_model=PythonClusteringResponse)
def cluster_by_run(request: PythonRunExecutionRequest) -> PythonClusteringResponse:
    try:
        metadata, items = load_run_and_embeddings(request.runId)
        return cluster_run(metadata, items)
    except ClusteringServiceError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    except ValueError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc
    except Exception as exc:  # pragma: no cover - last-resort guard
        raise HTTPException(status_code=500, detail=f"Unexpected clustering failure: {exc}") from exc
