from __future__ import annotations

from typing import Any

from app.case_epicrisis.application.curation import (
    apply_curation_decision,
    curation_context_payload,
    curation_from_context,
)
from app.case_epicrisis.application.rules import HistoriaClinicaRequiredRule
from app.case_epicrisis.application.use_cases import (
    BuildCaseEpicrisisContextUseCase,
    EvaluateEpicrisisRulesUseCase,
    GetCaseEpicrisisContextUseCase,
    UpdateCaseEpicrisisDraftUseCase,
)
from app.case_epicrisis.application.utils import normalize_context_payload
from app.case_epicrisis.domain.curation import CurationDecisionType, dump_curation_model
from app.case_epicrisis.infrastructure.gateways import (
    ServicesEpicrisisCodingGateway,
)
from app.case_epicrisis.infrastructure.medication_pertinence import LLMMedicationPertinenceReviewer
from app.case_epicrisis.infrastructure.repositories import (
    MongoCaseDocumentsReader,
    MongoCaseEpicrisisCacheRepository,
)
from app.core.logging import bind_log_context, get_audit_logger


class CaseEpicrisisService:
    """Fachada compatible mientras la lógica migra al módulo hexagonal."""

    def __init__(
        self,
        *,
        mongo_analyses: Any,
        client_groq: Any,
        client_gemini: Any = None,
        soat_retriever: Any = None,
        cie10_retriever: Any = None,
        llm_router: Any = None,
        colombia_tz: Any,
        llm_task_cache_repository: Any = None,
        catalog_registry: Any = None,
    ):
        self.audit_logger = get_audit_logger()
        self.catalog_registry = catalog_registry
        self.documents_reader = MongoCaseDocumentsReader(mongo_analyses)
        self.cache_repository = MongoCaseEpicrisisCacheRepository(
            mongo_analyses,
            colombia_tz,
            catalog_registry=catalog_registry,
        )
        self.coding_gateway = ServicesEpicrisisCodingGateway(
            client_groq=client_groq,
            client_gemini=client_gemini,
            soat_retriever=soat_retriever,
            cie10_retriever=cie10_retriever,
            llm_router=llm_router,
            llm_task_cache_repository=llm_task_cache_repository,
        )
        self.rules_evaluator = EvaluateEpicrisisRulesUseCase(rules=[HistoriaClinicaRequiredRule()])
        self.medication_pertinence_reviewer = (
            LLMMedicationPertinenceReviewer(llm_router) if llm_router is not None else None
        )
        self.build_case_context_use_case = BuildCaseEpicrisisContextUseCase(
            documents_reader=self.documents_reader,
            coding_gateway=self.coding_gateway,
            rules_evaluator=self.rules_evaluator,
            medication_pertinence_reviewer=self.medication_pertinence_reviewer,
        )
        self.get_case_context_use_case = GetCaseEpicrisisContextUseCase(
            cache_repository=self.cache_repository,
            build_case_context_use_case=self.build_case_context_use_case,
        )
        self.update_case_draft_use_case = UpdateCaseEpicrisisDraftUseCase(
            cache_repository=self.cache_repository,
            get_case_context_use_case=self.get_case_context_use_case,
        )

    def ensure_indexes(self) -> None:
        self.cache_repository.ensure_indexes()

    def build_case_context(self, username: str, case_key: str) -> dict[str, Any]:
        bind_log_context(username=username, case_key=case_key, document_type="epicrisis")
        existing = self.cache_repository.get(username, case_key)
        preserved_context = existing.get("contexto") if existing else None
        context = self.build_case_context_use_case.execute(
            username,
            case_key,
            preserved_context=preserved_context,
        )
        self.audit_logger.business_event(
            event_type="epicrisis.generated",
            action="build_case_context",
            outcome="success",
            service="case_epicrisis_service",
            resource={"case_key": case_key},
        )
        return context

    def get_cached_case_context(self, username: str, case_key: str) -> dict[str, Any] | None:
        bind_log_context(username=username, case_key=case_key, document_type="epicrisis")
        cache_doc = self.cache_repository.get(username, case_key)
        if not cache_doc or not isinstance(cache_doc.get("contexto"), dict):
            return cache_doc
        normalized_doc = dict(cache_doc)
        normalized_doc["contexto"] = normalize_context_payload(cache_doc["contexto"])
        return normalized_doc

    def cache_case_context(
        self,
        username: str,
        case_key: str,
        *,
        regen: bool = False,
    ) -> dict[str, Any]:
        bind_log_context(username=username, case_key=case_key, document_type="epicrisis")
        context = self.get_case_context_use_case.execute(
            username,
            case_key,
            regen=regen,
        )
        self.audit_logger.business_event(
            event_type="epicrisis.cache_refresh" if regen else "epicrisis.generated",
            action="cache_case_context",
            outcome="success",
            service="case_epicrisis_service",
            resource={"case_key": case_key, "regen": bool(regen)},
        )
        return context

    def update_case_draft(
        self,
        username: str,
        case_key: str,
        *,
        payload: dict[str, Any],
    ) -> dict[str, Any]:
        bind_log_context(username=username, case_key=case_key, document_type="epicrisis")
        result = self.update_case_draft_use_case.execute(
            username,
            case_key,
            payload=payload,
        )
        self.audit_logger.business_event(
            event_type="epicrisis.draft_updated",
            action="update_case_draft",
            outcome="success",
            service="case_epicrisis_service",
            resource={"case_key": case_key},
        )
        return result

    def get_case_curation(self, username: str, case_key: str) -> dict[str, Any]:
        bind_log_context(username=username, case_key=case_key, document_type="epicrisis")
        context = self.get_case_context_use_case.execute(username, case_key, regen=False)
        curation = curation_from_context(context)
        if curation is None:
            return {
                "curation_schema_version": "",
                "curation_version": "",
                "diagnosticos_curados": [],
                "procedimientos_curados": [],
                "conflictos_curacion": [],
                "pendientes_curacion": [],
                "catalogos_utilizados": [],
                "curation_generation_blocked": False,
                "curation_blocking_reason": "",
            }
        return curation_context_payload(curation)

    def update_case_curation_item(
        self,
        username: str,
        case_key: str,
        *,
        item_id: str,
        decision: str,
        expected_version: str,
        corrected_code: str = "",
        corrected_description: str = "",
        reason: str = "",
    ) -> dict[str, Any]:
        bind_log_context(username=username, case_key=case_key, document_type="epicrisis")
        context = self.get_case_context_use_case.execute(username, case_key, regen=False)
        curation = curation_from_context(context)
        if curation is None:
            raise LookupError("El caso no tiene datos objetivos para curar.")
        updated = apply_curation_decision(
            curation,
            item_id=item_id,
            decision=CurationDecisionType(decision),
            actor=username,
            expected_version=expected_version,
            corrected_code=corrected_code,
            corrected_description=corrected_description,
            reason=reason,
        )
        context.update(curation_context_payload(updated))
        self.cache_repository.upsert(
            username=username,
            case_key=case_key,
            context=context,
            regen_requested=False,
        )
        self.audit_logger.business_event(
            event_type="epicrisis.curation_decision",
            action="update_case_curation_item",
            outcome="success",
            service="case_epicrisis_service",
            resource={"case_key": case_key, "item_id": item_id, "decision": decision},
        )
        return dump_curation_model(updated)
