from __future__ import annotations

from copy import deepcopy
from typing import Any


EPICRISIS_EVIDENCE_COLLECTION = "epicrisis_case_evidence"


class InMemoryEpicrisisEvidenceRepository:
    """Adaptador pequeño para pruebas y entornos sin una base Mongo disponible."""

    def __init__(self) -> None:
        self._records: dict[tuple[str, str, str], dict[str, Any]] = {}

    def ensure_indexes(self) -> None:
        return None

    def upsert_many(self, *, username: str, case_key: str, records: list[dict[str, Any]]) -> None:
        for record in records:
            evidence_id = str(record.get("evidence_id") or "").strip()
            if evidence_id:
                self._records[(username, case_key, evidence_id)] = deepcopy(record)

    def get_many(self, *, username: str, case_key: str, evidence_ids: list[str]) -> dict[str, dict[str, Any]]:
        return {
            evidence_id: deepcopy(self._records[(username, case_key, evidence_id)])
            for evidence_id in evidence_ids
            if (username, case_key, evidence_id) in self._records
        }

    def delete_case(self, *, username: str, case_key: str) -> int:
        keys = [key for key in self._records if key[:2] == (username, case_key)]
        for key in keys:
            del self._records[key]
        return len(keys)


class MongoEpicrisisEvidenceRepository:
    def __init__(self, mongo_analyses: Any):
        self.mongo_analyses = mongo_analyses
        self.collection = self._resolve_collection(mongo_analyses)
        self._fallback = InMemoryEpicrisisEvidenceRepository() if self.collection is None else None

    @staticmethod
    def _resolve_collection(mongo_analyses: Any) -> Any:
        try:
            database = mongo_analyses.collection.database
            return database[EPICRISIS_EVIDENCE_COLLECTION]
        except (AttributeError, KeyError, TypeError):
            return None

    def ensure_indexes(self) -> None:
        if self._fallback is not None:
            self._fallback.ensure_indexes()
            return
        self.collection.create_index(
            [("usuario", 1), ("case_key", 1), ("evidence_id", 1)],
            unique=True,
        )

    def upsert_many(self, *, username: str, case_key: str, records: list[dict[str, Any]]) -> None:
        if self._fallback is not None:
            self._fallback.upsert_many(username=username, case_key=case_key, records=records)
            return
        for record in records:
            evidence_id = str(record.get("evidence_id") or "").strip()
            if not evidence_id:
                continue
            self.collection.update_one(
                {
                    "usuario": username,
                    "case_key": case_key,
                    "evidence_id": evidence_id,
                },
                {
                    "$set": {
                        "usuario": username,
                        "case_key": case_key,
                        "evidence_id": evidence_id,
                        "evidencia": record,
                    }
                },
                upsert=True,
            )

    def get_many(self, *, username: str, case_key: str, evidence_ids: list[str]) -> dict[str, dict[str, Any]]:
        if self._fallback is not None:
            return self._fallback.get_many(
                username=username,
                case_key=case_key,
                evidence_ids=evidence_ids,
            )
        if not evidence_ids:
            return {}
        cursor = self.collection.find(
            {
                "usuario": username,
                "case_key": case_key,
                "evidence_id": {"$in": list(dict.fromkeys(evidence_ids))},
            }
        )
        result: dict[str, dict[str, Any]] = {}
        for item in cursor:
            evidence_id = str(item.get("evidence_id") or "").strip()
            payload = item.get("evidencia")
            if evidence_id and isinstance(payload, dict):
                result[evidence_id] = deepcopy(payload)
        return result

    def delete_case(self, *, username: str, case_key: str) -> int:
        if self._fallback is not None:
            return self._fallback.delete_case(username=username, case_key=case_key)
        result = self.collection.delete_many({"usuario": username, "case_key": case_key})
        return int(getattr(result, "deleted_count", 0) or 0)
