from __future__ import annotations

import unittest
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch

from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from httpx import ASGITransport, AsyncClient

from app.auth import get_current_user
from app.routes import dashboard


class FakeListUserBatches:
    def __init__(self, batches: list[dict] | None = None) -> None:
        self._batches = list(batches or [])

    def execute(self, username: str, *, limit: int = 20) -> list[dict]:
        return self._batches[:limit]


class FakeDemoIdentityService:
    enabled = True

    def project_case_identity(
        self,
        *,
        username: str,
        case_key: str,
        case_number: str = "",
        patient_id: str = "",
        patient_name: str = "",
    ) -> dict[str, str]:
        if case_key == "CASE-001":
            return {
                "case_key": "00001-paciente-01-caso-00001",
                "case_number": case_number,
                "patient_id": "00001",
                "patient_name": "paciente-01",
                "nombre_paciente": "paciente-01",
            }
        return {
            "case_key": case_key,
            "case_number": case_number,
            "patient_id": patient_id,
            "patient_name": patient_name,
            "nombre_paciente": patient_name,
        }

    def project_document(self, *, username: str, document: dict | None):
        return document


class DashboardPageTest(unittest.IsolatedAsyncioTestCase):
    async def asyncSetUp(self) -> None:
        self.app = FastAPI()
        self.app.include_router(dashboard.router)

        async def override_current_user():
            return SimpleNamespace(username="admin", role="admin")

        self.app.dependency_overrides[get_current_user] = override_current_user
        self.app.state.services = SimpleNamespace(
            templates=Jinja2Templates(directory=str(Path(__file__).resolve().parents[1] / "web")),
            batch_runtime=SimpleNamespace(list_user_batches=FakeListUserBatches()),
        )
        self.transport = ASGITransport(app=self.app)

    async def asyncTearDown(self) -> None:
        self.app.dependency_overrides.clear()

    async def test_dashboard_renders_design_system_assets_and_admin_nav(self) -> None:
        async with AsyncClient(transport=self.transport, base_url="http://testserver") as client:
            response = await client.get("/dashboard")

        self.assertEqual(response.status_code, 200)
        self.assertIn("/static/css/globals.css", response.text)
        self.assertIn("/static/css/dashboard.css", response.text)
        self.assertEqual(response.text.count("/static/js/auth-guard.js"), 1)
        self.assertIn("/static/js/case-upload-dialog.js", response.text)
        self.assertIn("/static/js/dashboard.js", response.text)
        self.assertNotIn("data-app-shell-sidebar", response.text)
        self.assertNotIn("/static/js/app-shell.js", response.text)
        self.assertNotIn('class="ui-header__leading"', response.text)
        self.assertIn("Acciones rápidas", response.text)
        self.assertIn("Prefactura", response.text)
        self.assertIn('data-case-upload-open="prefactura"', response.text)
        self.assertIn("data-case-upload-prefactura-form", response.text)
        self.assertIn("Carga masiva ZIP", response.text)
        self.assertNotIn("Documentos del caso", response.text)
        self.assertIn("Panel admin", response.text)
        self.assertIn("data-user-menu-root", response.text)
        self.assertIn("data-case-upload-dialog", response.text)
        self.assertIn("data-case-upload-case-picker", response.text)
        self.assertIn("data-case-upload-case-search", response.text)
        self.assertIn("data-case-upload-case-select", response.text)
        self.assertIn("data-case-upload-retry", response.text)
        self.assertIn("Reintentar procesamiento", response.text)
        self.assertIn("Lotes recientes", response.text)
        self.assertEqual(response.text.count("data-dashboard-collapse-button"), 3)
        self.assertIn('aria-controls="dashboard-activity-panel"', response.text)
        self.assertIn('aria-controls="dashboard-cases-panel"', response.text)
        self.assertIn('aria-controls="dashboard-batches-panel"', response.text)
        self.assertEqual(response.text.count('aria-expanded="true"'), 3)
        self.assertNotIn('id="dashboard-quick-upload"', response.text)
        self.assertNotIn("/ver_historia?", response.text)
        self.assertNotIn("/subir_documento", response.text)
        self.assertNotIn("/epicrisis?id=", response.text)

    async def test_dashboard_overview_contract(self) -> None:
        snapshot = {
            "historias_por_paciente": {
                "Blanca Lija": [
                    {
                        "_id": "doc-1",
                        "nombre_archivo": "historia.pdf",
                        "tipo_documento": "historia_clinica",
                        "fecha_analisis": "2026-04-28T08:15:00",
                        "nombre_paciente": "Blanca Lija",
                    }
                ]
            },
            "historias_por_caso": {
                "CASE-001": {
                    "group_key": "CASE-001",
                    "case_key": "CASE-001",
                    "case_number": "HC-001",
                    "patient_name": "Blanca Lija",
                    "documentos": [
                        {
                            "_id": "doc-1",
                            "nombre_archivo": "historia.pdf",
                            "tipo_documento": "historia_clinica",
                            "fecha_analisis": "2026-04-28T08:15:00",
                        }
                    ],
                    "tipos_documento": ["historia_clinica"],
                    "ready_for_epicrisis": True,
                    "epicrisis_status": "completado",
                    "epicrisis_url": "/epicrisis?case_key=CASE-001",
                }
            },
        }
        self.app.state.services.batch_runtime = SimpleNamespace(
            list_user_batches=FakeListUserBatches(
                [
                    {
                        "batch_id": "batch-001",
                        "nombre_archivo": "lote-abril.zip",
                        "status": "completado_con_errores",
                        "created_at": "2026-04-28T07:10:00",
                        "updated_at": "2026-04-28T08:40:00",
                        "total_files": 12,
                        "associated_files": 10,
                        "pending_validation_files": 2,
                        "failed_files": 0,
                    }
                ]
            )
        )

        with patch("app.routes.dashboard.build_user_histories_snapshot", return_value=snapshot):
            async with AsyncClient(transport=self.transport, base_url="http://testserver") as client:
                response = await client.get("/api/dashboard/overview")

        self.assertEqual(response.status_code, 200)
        payload = response.json()
        self.assertEqual(payload["summary"]["patients"], 1)
        self.assertEqual(payload["summary"]["cases"], 1)
        self.assertEqual(payload["summary"]["completed_epicrisis"], 1)
        self.assertEqual(payload["recent_cases"][0]["case_key"], "CASE-001")
        self.assertEqual(payload["recent_activity"][0]["status"], "completado")
        self.assertEqual(payload["recent_batches"][0]["batch_id"], "batch-001")
        self.assertEqual(payload["recent_batches"][0]["status_variant"], "warning")

    async def test_dashboard_overview_projects_demo_aliases(self) -> None:
        snapshot = {
            "historias_por_paciente": {
                "Blanca Lija": [
                    {
                        "_id": "doc-1",
                        "nombre_archivo": "historia.pdf",
                        "tipo_documento": "historia_clinica",
                        "fecha_analisis": "2026-04-28T08:15:00",
                        "nombre_paciente": "Blanca Lija",
                    }
                ]
            },
            "historias_por_caso": {
                "CASE-001": {
                    "group_key": "CASE-001",
                    "case_key": "CASE-001",
                    "case_number": "HC-001",
                    "patient_name": "Blanca Lija",
                    "patient_id": "12345678",
                    "documentos": [
                        {
                            "_id": "doc-1",
                            "nombre_archivo": "historia.pdf",
                            "tipo_documento": "historia_clinica",
                            "fecha_analisis": "2026-04-28T08:15:00",
                        }
                    ],
                    "tipos_documento": ["historia_clinica"],
                    "ready_for_epicrisis": True,
                    "epicrisis_status": "completado",
                    "epicrisis_url": "/epicrisis?case_key=CASE-001",
                }
            },
        }
        self.app.state.services.demo_identity_service = FakeDemoIdentityService()

        with patch("app.routes.dashboard.build_user_histories_snapshot", return_value=snapshot):
            async with AsyncClient(transport=self.transport, base_url="http://testserver") as client:
                response = await client.get("/api/dashboard/overview")

        self.assertEqual(response.status_code, 200)
        payload = response.json()
        self.assertEqual(payload["recent_cases"][0]["case_key"], "00001-paciente-01-caso-00001")
        self.assertEqual(payload["recent_cases"][0]["patient_name"], "paciente-01")

    async def test_dashboard_overview_sorts_mixed_naive_and_aware_datetimes(self) -> None:
        snapshot = {
            "historias_por_paciente": {
                "Paciente Uno": [
                    {
                        "_id": "doc-1",
                        "nombre_archivo": "historia-1.pdf",
                        "tipo_documento": "historia_clinica",
                        "fecha_analisis": "2026-04-28T08:15:00",
                        "nombre_paciente": "Paciente Uno",
                    }
                ],
                "Paciente Dos": [
                    {
                        "_id": "doc-2",
                        "nombre_archivo": "historia-2.pdf",
                        "tipo_documento": "factura",
                        "fecha_analisis": "2026-04-28T09:20:00-05:00",
                        "nombre_paciente": "Paciente Dos",
                    }
                ],
            },
            "historias_por_caso": {
                "CASE-001": {
                    "group_key": "CASE-001",
                    "case_key": "CASE-001",
                    "case_number": "HC-001",
                    "patient_name": "Paciente Uno",
                    "documentos": [
                        {
                            "_id": "doc-1",
                            "nombre_archivo": "historia-1.pdf",
                            "tipo_documento": "historia_clinica",
                            "fecha_analisis": "2026-04-28T08:15:00",
                        }
                    ],
                    "tipos_documento": ["historia_clinica"],
                    "ready_for_epicrisis": True,
                    "epicrisis_status": "completado",
                    "epicrisis_url": "/epicrisis?case_key=CASE-001",
                },
                "CASE-002": {
                    "group_key": "CASE-002",
                    "case_key": "CASE-002",
                    "case_number": "HC-002",
                    "patient_name": "Paciente Dos",
                    "documentos": [
                        {
                            "_id": "doc-2",
                            "nombre_archivo": "historia-2.pdf",
                            "tipo_documento": "factura",
                            "fecha_analisis": "2026-04-28T09:20:00-05:00",
                        }
                    ],
                    "tipos_documento": ["factura"],
                    "ready_for_epicrisis": False,
                    "epicrisis_status": "pendiente",
                    "epicrisis_url": "/epicrisis?case_key=CASE-002",
                },
            },
        }

        with patch("app.routes.dashboard.build_user_histories_snapshot", return_value=snapshot):
            async with AsyncClient(transport=self.transport, base_url="http://testserver") as client:
                response = await client.get("/api/dashboard/overview")

        self.assertEqual(response.status_code, 200)
        payload = response.json()
        self.assertEqual(payload["recent_cases"][0]["case_key"], "CASE-002")

    async def test_dashboard_search_contract(self) -> None:
        snapshot = {
            "historias_por_paciente": {
                "Maria Rodriguez": [
                    {
                        "_id": "doc-2",
                        "nombre_archivo": "factura_medica.pdf",
                        "tipo_documento": "factura",
                        "fecha_analisis": "2026-04-27T18:10:00",
                        "nombre_paciente": "Maria Rodriguez",
                    }
                ]
            },
            "historias_por_caso": {
                "CASE-002": {
                    "group_key": "CASE-002",
                    "case_key": "CASE-002",
                    "case_number": "HC-002",
                    "patient_name": "Maria Rodriguez",
                    "documentos": [
                        {
                            "_id": "doc-2",
                            "nombre_archivo": "factura_medica.pdf",
                            "tipo_documento": "factura",
                            "fecha_analisis": "2026-04-27T18:10:00",
                            "nombre_paciente": "Maria Rodriguez",
                        }
                    ],
                    "tipos_documento": ["factura"],
                    "ready_for_epicrisis": False,
                    "epicrisis_status": "pendiente",
                    "epicrisis_url": "/epicrisis?case_key=CASE-002",
                }
            },
        }

        with patch("app.routes.dashboard.build_user_histories_snapshot", return_value=snapshot):
            async with AsyncClient(transport=self.transport, base_url="http://testserver") as client:
                response = await client.get("/api/dashboard/search?q=factura")

        self.assertEqual(response.status_code, 200)
        payload = response.json()
        self.assertEqual(payload["query"], "factura")
        kinds = {item["kind"] for item in payload["results"]}
        self.assertIn("document", kinds)
        self.assertIn("patient", kinds)


if __name__ == "__main__":
    unittest.main()
