from __future__ import annotations

from typing import Any

from pymongo.errors import OperationFailure

from app.migrations.runner import Migration


def _safe_create_index(collection: Any, keys: list[tuple[str, int]], **kwargs: Any) -> None:
    try:
        collection.create_index(keys, **kwargs)
    except OperationFailure as exc:
        if getattr(exc, "code", None) not in {85, 86}:
            raise


def _deduplicate_case_caches(collection: Any) -> None:
    duplicates = collection.aggregate(
        [
            {
                "$match": {
                    "tipo_documento": "epicrisis_case_cache",
                    "case_key": {"$exists": True, "$type": "string", "$ne": ""},
                }
            },
            {"$sort": {"fecha_analisis": -1, "_id": -1}},
            {
                "$group": {
                    "_id": {
                        "usuario": "$usuario",
                        "case_key": "$case_key",
                        "tipo_documento": "$tipo_documento",
                    },
                    "ids": {"$push": "$_id"},
                    "count": {"$sum": 1},
                }
            },
            {"$match": {"count": {"$gt": 1}}},
        ]
    )
    for item in duplicates:
        ids = list(item.get("ids") or [])
        if len(ids) >= 2:
            collection.delete_many({"_id": {"$in": ids[1:]}})


def _migration_20260507_01(database: Any) -> None:
    analyses = database["historias_analizadas"]
    audit_events = database["audit_events"]
    _safe_create_index(
        analyses,
        [("usuario", 1), ("case_key", 1), ("tipo_documento", 1), ("fecha_analisis", -1)],
    )
    _safe_create_index(analyses, [("usuario", 1), ("batch_file_id", 1)])
    _safe_create_index(
        analyses,
        [("usuario", 1), ("tipo_documento", 1), ("case_key", 1), ("version", -1)],
    )
    _safe_create_index(
        analyses,
        [("usuario", 1), ("tipo_documento", 1), ("template_scope_key", 1), ("version", -1)],
    )
    _deduplicate_case_caches(analyses)
    _safe_create_index(
        analyses,
        [("usuario", 1), ("tipo_documento", 1), ("case_key", 1)],
        unique=True,
        partialFilterExpression={
            "tipo_documento": "epicrisis_case_cache",
            "case_key": {"$exists": True, "$type": "string"},
        },
    )
    _safe_create_index(audit_events, [("timestamp", 1)])
    _safe_create_index(
        audit_events,
        [("expires_at", 1)],
        expireAfterSeconds=0,
        name="audit_events_ttl",
    )


def _migration_20260507_02(database: Any) -> None:
    processing_batches = database["processing_batches"]
    processing_batch_files = database["processing_batch_files"]
    processing_batch_cases = database["processing_batch_cases"]

    _safe_create_index(processing_batches, [("created_at", -1)])
    _safe_create_index(processing_batches, [("usuario", 1), ("updated_at", -1)])

    _safe_create_index(processing_batch_files, [("batch_id", 1), ("status", 1)])
    _safe_create_index(processing_batch_files, [("batch_id", 1), ("case_key", 1)])
    _safe_create_index(processing_batch_files, [("batch_id", 1), ("created_at", 1)])
    _safe_create_index(processing_batch_files, [("batch_id", 1), ("clinical_status", 1)])
    _safe_create_index(processing_batch_files, [("analysis_document_id", 1)])

    _safe_create_index(processing_batch_cases, [("batch_id", 1), ("case_key", 1)])
    _safe_create_index(processing_batch_cases, [("batch_id", 1), ("patient_name", 1)])
    _safe_create_index(processing_batch_cases, [("usuario", 1), ("case_key", 1)])


def _migration_20260622_01(database: Any) -> None:
    llm_task_cache = database["llm_task_cache"]
    _safe_create_index(
        llm_task_cache,
        [("usuario", 1), ("task", 1), ("fingerprint", 1)],
        unique=True,
        partialFilterExpression={
            "tipo_documento": "llm_task_cache",
            "usuario": {"$exists": True, "$type": "string"},
            "task": {"$exists": True, "$type": "string"},
            "fingerprint": {"$exists": True, "$type": "string"},
        },
    )
    _safe_create_index(llm_task_cache, [("expires_at", 1)], expireAfterSeconds=0)
    _safe_create_index(llm_task_cache, [("created_at", -1)])


def _migration_20260622_02_demo_identity_aliases(database: Any) -> None:
    demo_identity_aliases = database["demo_identity_aliases"]
    _safe_create_index(
        demo_identity_aliases,
        [("kind", 1), ("scope", 1)],
        unique=True,
        partialFilterExpression={
            "kind": "counter",
            "scope": {"$exists": True, "$type": "string"},
        },
    )
    _safe_create_index(
        demo_identity_aliases,
        [("kind", 1), ("real_patient_key", 1)],
        unique=True,
        partialFilterExpression={
            "kind": "patient_alias",
            "real_patient_key": {"$exists": True, "$type": "string"},
        },
    )
    _safe_create_index(
        demo_identity_aliases,
        [("kind", 1), ("real_case_key", 1)],
        unique=True,
        partialFilterExpression={
            "kind": "case_alias",
            "real_case_key": {"$exists": True, "$type": "string"},
        },
    )
    _safe_create_index(
        demo_identity_aliases,
        [("kind", 1), ("demo_case_key", 1)],
        unique=True,
        partialFilterExpression={
            "kind": "case_alias",
            "demo_case_key": {"$exists": True, "$type": "string"},
        },
    )
    _safe_create_index(
        demo_identity_aliases,
        [("kind", 1), ("demo_patient_name", 1)],
        partialFilterExpression={
            "kind": "patient_alias",
            "demo_patient_name": {"$exists": True, "$type": "string"},
        },
    )


MIGRATIONS = [
    Migration(
        version="20260507_01_core_indexes",
        description="Create core analysis, cache, rips and audit indexes.",
        apply=_migration_20260507_01,
    ),
    Migration(
        version="20260507_02_batch_indexes",
        description="Create batch processing indexes.",
        apply=_migration_20260507_02,
    ),
    Migration(
        version="20260622_01_llm_task_cache_collection",
        description="Create dedicated indexes for backend-only LLM task cache storage.",
        apply=_migration_20260622_01,
    ),
    Migration(
        version="20260622_02_demo_identity_aliases",
        description="Create backend-only demo identity alias indexes.",
        apply=_migration_20260622_02_demo_identity_aliases,
    ),
]
