from __future__ import annotations

from dataclasses import dataclass

from app.rips.application.builders import build_rips_payload
from app.rips.application.models import (
    GenerateCaseRipsCommand,
    GeneratedRipsPayload,
    RipsValidationReport,
)
from app.rips.application.validation import validate_rips_payload
from app.rips.domain.models import RipsPayload
from app.rips.domain.ports import CaseEpicrisisContextProvider, RipsPayloadRepository


@dataclass
class GenerateCaseRipsUseCase:
    context_provider: CaseEpicrisisContextProvider
    repository: RipsPayloadRepository

    def _build_export_metadata(self, validation_report: RipsValidationReport) -> tuple[str, str]:
        if validation_report.ready_for_cuv:
            return ("ready", "El JSON puede pasar a revisión final.")
        return ("preliminary", "El caso requiere ajuste antes de CUV. El archivo se considera preliminar.")

    def _build_cached_result(self, case_key: str, existing: dict) -> GeneratedRipsPayload:
        payload = dict(existing.get("payload") or {})
        payload_model = RipsPayload(**payload)
        validation_report = existing.get("validation_report")
        field_trace_map = list(existing.get("field_trace_map") or [])
        resolved_report = (
            RipsValidationReport(**validation_report)
            if isinstance(validation_report, dict)
            else validate_rips_payload(payload_model)
        )
        export_status, export_message = self._build_export_metadata(resolved_report)
        return GeneratedRipsPayload(
            case_key=case_key,
            version=existing.get("version"),
            stored=True,
            regenerated=False,
            source="cache",
            export_status=export_status,
            export_message=export_message,
            payload=payload,
            validation_report=resolved_report,
            field_trace_map=field_trace_map,
        )

    def get_latest(self, username: str, case_key: str) -> GeneratedRipsPayload | None:
        existing = self.repository.get_latest(username, case_key)
        if not existing:
            return None
        return self._build_cached_result(case_key, existing)

    def execute(self, command: GenerateCaseRipsCommand) -> GeneratedRipsPayload:
        existing = self.repository.get_latest(command.username, command.case_key)
        if existing and not command.regen:
            return self._build_cached_result(command.case_key, existing)

        context = self.context_provider.get_case_context(
            command.username,
            command.case_key,
            regen=command.regen,
        )
        built_payload = build_rips_payload(context=context, options=command.options)
        validation_report = validate_rips_payload(built_payload.payload, source_context=context)
        serialized_payload = built_payload.payload.model_dump(mode="python", exclude_none=True)
        serialized_validation_report = validation_report.model_dump(mode="python", exclude_none=True)
        serialized_field_trace_map = [
            item.model_dump(mode="python", exclude_none=True) for item in built_payload.field_trace_map
        ]

        version = None
        if command.persist:
            saved = self.repository.save_version(
                username=command.username,
                case_key=command.case_key,
                payload=serialized_payload,
                validation_report=serialized_validation_report,
                field_trace_map=serialized_field_trace_map,
                source_context=context,
                regen_requested=command.regen,
            )
            version = saved.get("version")
        export_status, export_message = self._build_export_metadata(validation_report)

        return GeneratedRipsPayload(
            case_key=command.case_key,
            version=version,
            stored=command.persist,
            regenerated=command.regen,
            source="generated",
            export_status=export_status,
            export_message=export_message,
            payload=serialized_payload,
            validation_report=validation_report,
            field_trace_map=built_payload.field_trace_map,
        )
