from __future__ import annotations

import os
import subprocess
import sys
import textwrap
import unittest
from types import SimpleNamespace
from unittest.mock import patch

from app.services.clinical_document_service import ClinicalDocumentService


def _run_import_check(module_name: str) -> subprocess.CompletedProcess[str]:
    code = textwrap.dedent(
        f"""
        import importlib
        import sys

        importlib.import_module({module_name!r})
        print("modules.processing.resumen_google" in sys.modules)
        """
    )
    env = os.environ.copy()
    env["HF_HUB_OFFLINE"] = "1"
    env["TRANSFORMERS_OFFLINE"] = "1"
    return subprocess.run(
        [sys.executable, "-c", code],
        capture_output=True,
        cwd=os.getcwd(),
        env=env,
        text=True,
        timeout=60,
        check=False,
    )


class StartupLazyImportTest(unittest.TestCase):
    def test_importing_main_does_not_load_legacy_historia_module(self) -> None:
        result = _run_import_check("app.main")

        self.assertEqual(result.returncode, 0, msg=result.stderr)
        self.assertEqual(result.stdout.strip(), "False")

    def test_importing_celery_app_does_not_load_legacy_historia_module(self) -> None:
        result = _run_import_check("app.batch_processing.celery_app")

        self.assertEqual(result.returncode, 0, msg=result.stderr)
        self.assertEqual(result.stdout.strip(), "False")


class ClinicalDocumentServiceHistoryAnalysisTest(unittest.TestCase):
    def _build_service(self) -> ClinicalDocumentService:
        service = ClinicalDocumentService.__new__(ClinicalDocumentService)
        service.client_groq = SimpleNamespace()
        service.client_gemini = None
        return service

    def test_historia_clinica_analysis_uses_lazy_loader(self) -> None:
        service = self._build_service()

        class FakeHistoriaClinicaRequest:
            @staticmethod
            def analizar_historiaclinica(raw_text: str) -> str:
                return f"<p>{raw_text}</p>"

        with patch(
            "app.services.clinical_document_service._load_historia_clinica_request_class",
            return_value=FakeHistoriaClinicaRequest,
        ):
            html, error = service._generate_analysis("texto clinico", "historia_clinica")

        self.assertEqual(html, "<p>texto clinico</p>")
        self.assertIsNone(error)

    def test_historia_clinica_analysis_preserves_generic_fallback_when_lazy_loader_fails(self) -> None:
        service = self._build_service()

        class FailingHistoriaClinicaRequest:
            @staticmethod
            def analizar_historiaclinica(raw_text: str) -> str:
                raise RuntimeError("boom")

        with patch(
            "app.services.clinical_document_service._load_historia_clinica_request_class",
            return_value=FailingHistoriaClinicaRequest,
        ), patch(
            "app.services.clinical_document_service.procesar_documento_generico",
            return_value="<p>fallback</p>",
        ) as fallback_mock, patch(
            "app.services.clinical_document_service.audit_logger.llm_event"
        ) as llm_event_mock:
            html, error = service._generate_analysis("texto clinico", "historia_clinica")

        self.assertEqual(html, "<p>fallback</p>")
        self.assertEqual(error, "boom")
        fallback_mock.assert_called_once_with(
            "texto clinico",
            "historia_clinica",
            service.client_groq,
            service.client_gemini,
            force_provider=None,
        )
        llm_event_mock.assert_called_once()
