"""Phase-2 chart and houses routes."""
from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Request

from moira import Moira

from ..cache import ChartLRUCache, cached_response
from ..dependencies import get_engine
from ..models.chart import (
    AnalyticalHouseDynamicsRequest,
    AnalyticalHouseDynamicsResponse,
    ChartReductionResponse,
    ChartRequest,
    ChartWithComputationTruthResponse,
    HouseDynamicsFromArmcRequest,
    HouseDynamicsRequest,
    HouseDynamicsResponse,
    HousesReductionResponse,
    HousesRequest,
    HousesWithComputationTruthResponse,
    PolarAdmissibilityRequest,
    PolarAdmissibilityResponse,
)
from ..serializers.chart import (
    serialize_analytical_house_dynamics,
    serialize_chart_with_computation_truth,
    serialize_chart_with_reduction,
    serialize_house_dynamics,
    serialize_houses_with_computation_truth,
    serialize_houses_with_reduction,
    serialize_polar_admissibility,
)
from ..services.chart import (
    UnsupportedPolarHouseSystemError,
    compute_analytical_house_dynamics,
    compute_chart_with_reduction,
    compute_house_dynamics,
    compute_house_dynamics_from_armc,
    compute_houses_with_reduction,
    compute_polar_admissibility,
)


router = APIRouter(prefix="/v1", tags=["chart"])


def _get_cache(request: Request) -> ChartLRUCache | None:
    """Return the per-process chart cache, or None if not initialised."""
    return getattr(request.app.state, "chart_cache", None)


@router.post("/chart", response_model=ChartWithComputationTruthResponse)
def chart_route(
    request: ChartRequest,
    http_request: Request,
    engine: Moira = Depends(get_engine),
) -> ChartWithComputationTruthResponse:
    """Serialize a canonical chart result with additive computation truth."""

    def compute_response() -> ChartWithComputationTruthResponse:
        chart, reduction = compute_chart_with_reduction(engine, request)
        return serialize_chart_with_computation_truth(chart, reduction)

    return cached_response(
        _get_cache(http_request),
        "v1:chart",
        request,
        engine,
        compute_response,
    )


@router.post("/chart/reduction", response_model=ChartReductionResponse)
def chart_reduction_route(
    request: ChartRequest,
    http_request: Request,
    engine: Moira = Depends(get_engine),
) -> ChartReductionResponse:
    """Serialize a chart together with its reduction truth."""

    def compute_response() -> ChartReductionResponse:
        chart, reduction = compute_chart_with_reduction(engine, request)
        return serialize_chart_with_reduction(chart, reduction)

    return cached_response(
        _get_cache(http_request),
        "v1:chart:reduction",
        request,
        engine,
        compute_response,
    )


@router.post("/houses", response_model=HousesWithComputationTruthResponse)
def houses_route(
    request: HousesRequest,
    engine: Moira = Depends(get_engine),
) -> HousesWithComputationTruthResponse:
    """Serialize a canonical houses result with additive computation truth."""

    houses, reduction = compute_houses_with_reduction(engine, request)
    return serialize_houses_with_computation_truth(houses, reduction)


@router.post("/houses/reduction", response_model=HousesReductionResponse)
def houses_reduction_route(
    request: HousesRequest,
    engine: Moira = Depends(get_engine),
) -> HousesReductionResponse:
    """Serialize houses result together with the governing doctrine and computation path (reduction truth)."""
    houses, reduction = compute_houses_with_reduction(engine, request)
    return serialize_houses_with_reduction(houses, reduction)


@router.post("/houses/dynamics", response_model=HouseDynamicsResponse)
def house_dynamics_route(
    request: HouseDynamicsRequest,
    engine: Moira = Depends(get_engine),
) -> HouseDynamicsResponse:
    """Compute instantaneous house cusp and angle speeds."""
    dynamics = compute_house_dynamics(engine, request)
    return serialize_house_dynamics(dynamics)


@router.post("/houses/dynamics/armc", response_model=HouseDynamicsResponse)
def house_dynamics_from_armc_route(
    request: HouseDynamicsFromArmcRequest,
) -> HouseDynamicsResponse:
    """Compute ARMC-native house dynamics with obliquity held fixed."""

    return serialize_house_dynamics(compute_house_dynamics_from_armc(request))


@router.post(
    "/houses/dynamics/analytical",
    response_model=AnalyticalHouseDynamicsResponse,
)
def analytical_house_dynamics_route(
    request: AnalyticalHouseDynamicsRequest,
) -> AnalyticalHouseDynamicsResponse:
    """Compute exact analytical MC, ASC, and Vertex angle velocities."""

    return serialize_analytical_house_dynamics(
        compute_analytical_house_dynamics(request)
    )


@router.post("/houses/polar-admissibility", response_model=PolarAdmissibilityResponse)
def houses_polar_admissibility_route(
    request: PolarAdmissibilityRequest,
) -> PolarAdmissibilityResponse:
    """Scan and return the polar ARMC admissibility windows and quality metrics for a house system."""
    try:
        result = compute_polar_admissibility(request)
    except UnsupportedPolarHouseSystemError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    return serialize_polar_admissibility(result)
