"""Advisor Gemini para páginas ambiguas dentro de prefacturas compuestas."""

from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, Field

from app.batch_processing.domain.models import PrefacturaPageClassification
from app.batch_processing.domain.ports import PrefacturaClassificationAdvisor
from app.llm import LLMOutputKind, LLMStructuredRequest, LLMTask


class _PrefacturaAdvisorOutput(BaseModel):
    document_type: Literal["historia_clinica", "quirurgico", "laboratorio", "radiologia"]
    confidence: float = Field(ge=0.0, le=1.0)
    reason: str = ""
    evidence: list[str] = Field(default_factory=list)
    document_title: str = ""


class GeminiPrefacturaClassificationAdvisor(PrefacturaClassificationAdvisor):
    """Consulta Gemini solo cuando la heurística no cierra la página con confianza suficiente."""

    def __init__(self, *, llm_router: Any) -> None:
        self._llm_router = llm_router

    def classify_page(
        self,
        *,
        filename: str,
        page_number: int,
        page_text: str,
        detected_type: str,
        classifier_title: str,
        candidate_types: list[str],
    ) -> PrefacturaPageClassification | None:
        if self._llm_router is None:
            return None

        allowed_types = [
            item
            for item in candidate_types
            if item in {"historia_clinica", "quirurgico", "laboratorio", "radiologia"}
        ]
        if not allowed_types:
            return None

        prompt = self._build_prompt(
            filename=filename,
            page_number=page_number,
            page_text=page_text,
            detected_type=detected_type,
            classifier_title=classifier_title,
            candidate_types=allowed_types,
        )
        try:
            response = self._llm_router.generate_structured(
                LLMStructuredRequest(
                    task=LLMTask.PREFACTURA_PAGE_CLASSIFICATION,
                    prompt=prompt,
                    output_model=_PrefacturaAdvisorOutput,
                    output_kind=LLMOutputKind.STRUCTURED_OBJECT,
                    system_prompt=(
                        "Eres un clasificador documental determinista para páginas de prefactura compuesta. "
                        "Responde únicamente con JSON válido conforme al esquema pedido."
                    ),
                    metadata={
                        "filename": filename,
                        "page_number": str(page_number),
                        "candidate_types": ",".join(allowed_types),
                    },
                )
            )
        except Exception:
            return None

        content = response.content
        if not isinstance(content, _PrefacturaAdvisorOutput):
            content = _PrefacturaAdvisorOutput.model_validate(content)
        confidence = float(content.confidence or 0.0)
        return PrefacturaPageClassification(
            page_number=page_number,
            document_type=content.document_type,
            document_title=str(content.document_title or ""),
            confidence=confidence,
            evidence=list(content.evidence or []),
            reason=str(content.reason or ""),
            source="gemini",
            is_autonomous=content.document_type in {"quirurgico", "laboratorio", "radiologia"},
            page_text=page_text,
        )

    def _build_prompt(
        self,
        *,
        filename: str,
        page_number: int,
        page_text: str,
        detected_type: str,
        classifier_title: str,
        candidate_types: list[str],
    ) -> str:
        trimmed_text = str(page_text or "")[:5000]
        return (
            f"Archivo: {filename}\n"
            f"Página: {page_number}\n"
            f"Tipo provisional: {detected_type}\n"
            f"Título provisional: {classifier_title}\n"
            f"Tipos permitidos: {', '.join(candidate_types)}\n"
            "Instrucciones:\n"
            "- Elige el tipo documental más probable para esta página.\n"
            "- Devuelve confidence entre 0 y 1.\n"
            "- Explica brevemente la decisión.\n"
            "- Solo usa evidencias visibles en el texto.\n"
            "- Si la página corresponde a texto clínico general, elige historia_clinica.\n\n"
            f"Texto:\n{trimmed_text}"
        )
