from __future__ import annotations

from json import JSONDecodeError
from typing import TYPE_CHECKING, Annotated, Any

from fastapi import APIRouter, Depends, HTTPException, Request, Security
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from starlette.status import HTTP_202_ACCEPTED, HTTP_400_BAD_REQUEST, HTTP_404_NOT_FOUND

from app.auth import get_current_user
from app.core.dependencies import get_services
from app.models import UserInDB
from app.rda.domain.models import RdaArtifactType
from app.services.demo_identity_service import get_demo_identity_service


if TYPE_CHECKING:
    from app.core.services import AppServices
else:
    AppServices = Any


router = APIRouter()
CurrentUser = Annotated[UserInDB, Security(get_current_user)]
ServicesDep = Annotated[AppServices, Depends(get_services)]


def _normalize_case_key(case_key: str) -> str:
    normalized = str(case_key or "").strip()
    if not normalized:
        raise HTTPException(
            status_code=HTTP_400_BAD_REQUEST,
            detail="El parámetro 'case_key' es obligatorio.",
        )
    return normalized


def _serialize_result(result: Any, *, exclude_none: bool = True) -> dict[str, Any]:
    payload = (
        result.model_dump(mode="python", exclude_none=exclude_none)
        if hasattr(result, "model_dump")
        else result
    )
    serialized = jsonable_encoder(payload)
    return dict(serialized) if isinstance(serialized, dict) else {}


async def _resolve_force_flag(request: Request) -> bool:
    body = await request.body()
    if not body:
        return False
    try:
        payload = await request.json()
    except (JSONDecodeError, ValueError) as exc:
        raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail="Payload invalido.") from exc
    if not isinstance(payload, dict):
        raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail="Payload invalido.")
    return bool(payload.get("force", False))


def _resolve_real_case_key(*, services: ServicesDep, username: str, case_key: str) -> str:
    normalized = _normalize_case_key(case_key)
    return get_demo_identity_service(services).resolve_case_key(
        username=username,
        visible_case_key=normalized,
    )


def _project_case_key(*, services: ServicesDep, username: str, case_key: str) -> str:
    return str(
        get_demo_identity_service(services).project_case_identity(
            username=username,
            case_key=case_key,
        ).get("case_key", case_key)
    ).strip()


@router.post("/api/rda/cases/{case_key}/{artifact_type}")
async def queue_case_rda(
    case_key: str,
    artifact_type: RdaArtifactType,
    request: Request,
    current_user: CurrentUser,
    services: ServicesDep,
) -> JSONResponse:
    normalized_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        case_key=case_key,
    )
    result = services.rda_service.queue_case_rda(
        current_user.username,
        normalized_case_key,
        artifact_type,
        force=await _resolve_force_flag(request),
    )
    serialized = _serialize_result(result)
    serialized["case_key"] = _project_case_key(
        services=services,
        username=current_user.username,
        case_key=normalized_case_key,
    )
    return JSONResponse(status_code=HTTP_202_ACCEPTED, content=serialized)


@router.get("/api/rda/cases/{case_key}/{artifact_type}")
async def get_case_rda(
    case_key: str,
    artifact_type: RdaArtifactType,
    current_user: CurrentUser,
    services: ServicesDep,
) -> JSONResponse:
    normalized_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        case_key=case_key,
    )
    result = services.rda_service.get_latest_case_rda(
        current_user.username,
        normalized_case_key,
        artifact_type,
    )
    if result is None:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="No existe un artefacto RDA generado para este caso y tipo.",
        )
    serialized = _serialize_result(result)
    serialized["case_key"] = _project_case_key(
        services=services,
        username=current_user.username,
        case_key=normalized_case_key,
    )
    return JSONResponse(content=serialized)


@router.get("/api/rda/cases/{case_key}/{artifact_type}/status")
async def get_case_rda_status(
    case_key: str,
    artifact_type: RdaArtifactType,
    current_user: CurrentUser,
    services: ServicesDep,
) -> JSONResponse:
    normalized_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        case_key=case_key,
    )
    result = services.rda_service.get_case_rda_status(
        current_user.username,
        normalized_case_key,
        artifact_type,
    )
    if result is None:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="No existe un proceso RDA registrado para este caso y tipo.",
        )
    serialized = _serialize_result(result)
    serialized["case_key"] = _project_case_key(
        services=services,
        username=current_user.username,
        case_key=normalized_case_key,
    )
    return JSONResponse(content=serialized)


@router.get("/api/rda/cases/{case_key}/{artifact_type}/validation")
async def get_case_rda_validation(
    case_key: str,
    artifact_type: RdaArtifactType,
    current_user: CurrentUser,
    services: ServicesDep,
) -> JSONResponse:
    normalized_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        case_key=case_key,
    )
    result = services.rda_service.get_case_rda_validation(
        current_user.username,
        normalized_case_key,
        artifact_type,
    )
    if result is None:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="No existe artefacto ni proceso RDA registrado para este caso y tipo.",
        )
    serialized = _serialize_result(result, exclude_none=False)
    serialized["case_key"] = _project_case_key(
        services=services,
        username=current_user.username,
        case_key=normalized_case_key,
    )
    return JSONResponse(content=serialized)
