"""Scores router — scoring engine endpoints."""

from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession

from app.dependencies import get_db, require_access
from app.schemas.common import APIEnvelope
from app.schemas.score import (
    CompositeBreakdownResponse,
    DimensionScoreResponse,
    RankingEntry,
    RankingResponse,
    ScoreBreakdownResponse,
    ScoreResponse,
    SubScoreResponse,
    WeightUpdateRequest,
)
from app.services.scoring_service import get_rankings, get_score, update_weights


def _map_breakdown(raw: dict | None) -> ScoreBreakdownResponse | None:
    """Convert a raw breakdown dict from the scoring service into a Pydantic model."""
    if raw is None:
        return None
    return ScoreBreakdownResponse(
        sub_scores=[SubScoreResponse(**s) for s in raw.get("sub_scores", [])],
        formula=raw.get("formula", ""),
        unavailable=raw.get("unavailable", []),
    )


def _map_composite_breakdown(raw: dict | None) -> CompositeBreakdownResponse | None:
    """Convert a raw composite breakdown dict into a Pydantic model."""
    if raw is None:
        return None
    return CompositeBreakdownResponse(
        weights=raw["weights"],
        available_dimensions=raw["available_dimensions"],
        missing_dimensions=raw["missing_dimensions"],
        renormalized_weights=raw["renormalized_weights"],
        formula=raw["formula"],
        base_score=raw.get("base_score"),
        sentiment_score=raw.get("sentiment_score"),
        sentiment_adjustment=raw.get("sentiment_adjustment"),
        max_sentiment_adjustment=raw.get("max_sentiment_adjustment"),
    )

router = APIRouter(tags=["scores"])


@router.get("/scores/{symbol}", response_model=APIEnvelope)
async def read_score(
    symbol: str,
    _user=Depends(require_access),
    db: AsyncSession = Depends(get_db),
) -> APIEnvelope:
    """Get the latest persisted composite + dimension scores for a symbol."""
    result = await get_score(db, symbol)

    data = ScoreResponse(
        symbol=result["symbol"],
        composite_score=result["composite_score"],
        composite_stale=result["composite_stale"],
        weights=result["weights"],
        dimensions=[
            DimensionScoreResponse(
                dimension=d["dimension"],
                score=d["score"],
                is_stale=d["is_stale"],
                computed_at=d.get("computed_at"),
                breakdown=_map_breakdown(d.get("breakdown")),
            )
            for d in result["dimensions"]
        ],
        missing_dimensions=result["missing_dimensions"],
        computed_at=result["computed_at"],
        composite_breakdown=_map_composite_breakdown(
            result.get("composite_breakdown")
        ),
    )
    return APIEnvelope(status="success", data=data.model_dump(mode="json"))


@router.get("/rankings", response_model=APIEnvelope)
async def read_rankings(
    _user=Depends(require_access),
    db: AsyncSession = Depends(get_db),
) -> APIEnvelope:
    """Get all tickers ranked by composite score descending."""
    result = await get_rankings(db)

    data = RankingResponse(
        rankings=[
            RankingEntry(
                symbol=r["symbol"],
                composite_score=r["composite_score"],
                composite_stale=r.get("composite_stale", False),
                dimensions=[
                    DimensionScoreResponse(**d) for d in r["dimensions"]
                ],
            )
            for r in result["rankings"]
        ],
        weights=result["weights"],
    )
    return APIEnvelope(status="success", data=data.model_dump(mode="json"))


@router.put("/scores/weights", response_model=APIEnvelope)
async def update_score_weights(
    body: WeightUpdateRequest,
    _user=Depends(require_access),
    db: AsyncSession = Depends(get_db),
) -> APIEnvelope:
    """Update dimension weights and recompute all composite scores."""
    new_weights = await update_weights(db, body.weights)
    return APIEnvelope(status="success", data={"weights": new_weights})
