from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import Optional
import os

import pytz
from fastapi.templating import Jinja2Templates
from groq import Groq

from app.config import config, require_env
from app.batch_processing.infrastructure.runtime import BatchRuntime, build_batch_runtime
from app.core.gemini_client import get_gemini_model
from app.services.case_epicrisis_service import CaseEpicrisisService
from app.services.clinical_document_service import ClinicalDocumentService
from modules.data_collection.mongodb_storage import MongoDBStorage
from modules.processing.cie10.RANGES_HTML import CIE10Retriever
from modules.processing.cie10.RANGES_CUPS import CUPSRetriever
from modules.processing.soat.soat_retriever import SOATRetriever


COLOMBIA_TZ = pytz.timezone("America/Bogota")


@dataclass
class AppServices:
    templates: Jinja2Templates
    base_dir: Path
    mongo_storage: MongoDBStorage
    mongo_analyses: MongoDBStorage
    client_groq: Groq
    client_gemini: Optional[object]
    cie10_retriever: CIE10Retriever
    cups_retriever: CUPSRetriever
    soat_retriever: Optional[SOATRetriever]
    colombia_tz: pytz.BaseTzInfo
    clinical_document_service: ClinicalDocumentService
    case_epicrisis_service: CaseEpicrisisService
    batch_runtime: BatchRuntime


def _resolve_path(base_dir: Path, path_value: str) -> str:
    p = Path(path_value)
    return str(p if p.is_absolute() else (base_dir / p))


def build_services(base_dir: Path) -> AppServices:
    templates = Jinja2Templates(directory="web")

    mongo_storage = MongoDBStorage(
        config.MONGO_URI, config.DB_NAME, config.COLLECTION_NAME
    )
    mongo_analyses = MongoDBStorage(
        config.MONGO_URI, config.DB_NAME, "historias_analizadas"
    )

    client_groq = Groq(api_key=require_env(config.GROQ_API_KEY, "GROQ_API_KEY"))

    if config.GEMINI_API_KEY:
        client_gemini = get_gemini_model(
            api_key=require_env(config.GEMINI_API_KEY, "GEMINI_API_KEY"),
            model_name=config.GEMINI_MODEL_DEFAULT,
        )
    else:
        client_gemini = None

    cie10_index_path = os.getenv("CIE10_FAISS_INDEX", "faiss_principal_jerarquico")
    cie10_estructura_path = os.getenv(
        "CIE10_ESTRUCTURA_JSON", "cie10_estructura_completa.json"
    )
    cups_index_path = os.getenv("CUPS_FAISS_INDEX", "cups_faiss")

    cie10_retriever = CIE10Retriever(
        faiss_index_path=_resolve_path(base_dir, cie10_index_path),
        estructura_json_path=_resolve_path(base_dir, cie10_estructura_path),
        groq_api_key=config.GROQ_API_KEY,
        groq_model=config.GROQ_MODEL_CIE10,
    )
    cups_retriever = CUPSRetriever(
        faiss_index_path=_resolve_path(base_dir, cups_index_path),
        groq_api_key=config.GROQ_API_KEY,
        groq_model=config.GROQ_MODEL_CUPS,
    )

    soat_retriever = None
    soat_index_dir = "soat_faiss"
    try:
        if (base_dir / soat_index_dir).exists():
            soat_retriever = SOATRetriever(
                faiss_index_path=str(base_dir / soat_index_dir),
                groq_api_key=config.GROQ_API_KEY,
                groq_model=config.GROQ_MODEL_SOAT,
            )
    except Exception:
        soat_retriever = None

    mongo_analyses.collection.create_index(
        [("usuario", 1), ("case_key", 1), ("tipo_documento", 1), ("fecha_analisis", -1)]
    )
    mongo_analyses.collection.create_index([("usuario", 1), ("batch_file_id", 1)])

    clinical_document_service = ClinicalDocumentService(
        mongo_storage=mongo_storage,
        mongo_analyses=mongo_analyses,
        client_groq=client_groq,
        client_gemini=client_gemini,
        cie10_retriever=cie10_retriever,
        cups_retriever=cups_retriever,
        colombia_tz=COLOMBIA_TZ,
    )
    case_epicrisis_service = CaseEpicrisisService(
        mongo_analyses=mongo_analyses,
        client_groq=client_groq,
        soat_retriever=soat_retriever,
        colombia_tz=COLOMBIA_TZ,
    )
    case_epicrisis_service.ensure_indexes()

    batch_runtime = build_batch_runtime(
        base_dir,
        COLOMBIA_TZ,
        clinical_document_service=clinical_document_service,
        case_epicrisis_service=case_epicrisis_service,
    )

    return AppServices(
        templates=templates,
        base_dir=base_dir,
        mongo_storage=mongo_storage,
        mongo_analyses=mongo_analyses,
        client_groq=client_groq,
        client_gemini=client_gemini,
        cie10_retriever=cie10_retriever,
        cups_retriever=cups_retriever,
        soat_retriever=soat_retriever,
        colombia_tz=COLOMBIA_TZ,
        clinical_document_service=clinical_document_service,
        case_epicrisis_service=case_epicrisis_service,
        batch_runtime=batch_runtime,
    )
