"""Bootstrap del módulo batch y selección del dispatcher activo."""

from __future__ import annotations

import os
from dataclasses import dataclass
from pathlib import Path

from app.batch_processing.application.use_cases import (
    CreateBatchUploadUseCase,
    CreateManualBatchUploadUseCase,
    CreatePrefacturaBatchUploadUseCase,
    FinalizeBatchUseCase,
    GenerateBatchEpicrisisExcelUseCase,
    GetBatchStatusUseCase,
    ListBatchCasesUseCase,
    ListBatchFilesUseCase,
    ListPendingAssociationsUseCase,
    ListUserBatchesUseCase,
    MaterializeBatchFileUseCase,
    PrepareBatchUseCase,
    ProcessBatchFileUseCase,
    QueueBatchEpicrisisExcelUseCase,
    QueueBatchEpicrisisUseCase,
    QueueBatchFileClinicalUseCase,
    RecomputeBatchBulkEpicrisisUseCase,
    RecomputeBatchTotalsUseCase,
    RefreshBatchCasesUseCase,
    ResolveFileAssociationUseCase,
)
from app.batch_processing.infrastructure.batch_epicrisis_excel import (
    BatchEpicrisisExcelWorkbookBuilder,
)
from app.batch_processing.infrastructure.heuristic_association import (
    HeuristicCaseAssociationService,
)
from app.batch_processing.infrastructure.heuristic_classifier import (
    HeuristicDocumentClassifier,
)
from app.batch_processing.infrastructure.job_dispatchers import (
    CeleryBatchJobDispatcher,
    InProcessBatchJobDispatcher,
)
from app.batch_processing.infrastructure.local_artifacts import (
    LocalBatchArtifactCleaner,
    LocalBatchExcelReportStore,
    LocalBatchWorkingFileStore,
)
from app.batch_processing.infrastructure.mongo_repositories import (
    LocalBatchArchiveStore,
    MongoBatchCaseRepository,
    MongoBatchFileRepository,
    MongoBatchRepository,
)
from app.batch_processing.infrastructure.pdf_text_extractor import PdfTextExtractor
from app.batch_processing.infrastructure.prefactura_pdf import PyPdfPrefacturaExtractor
from app.batch_processing.infrastructure.zip_archive import SafeZipArchiveExtractor
from app.services.case_epicrisis_service import CaseEpicrisisService
from app.services.clinical_document_service import ClinicalDocumentService


@dataclass
class BatchRuntime:
    """Contenedor explícito de casos de uso expuestos al resto de la aplicación."""

    create_batch_upload: CreateBatchUploadUseCase
    create_manual_batch_upload: CreateManualBatchUploadUseCase
    create_prefactura_batch_upload: CreatePrefacturaBatchUploadUseCase
    prepare_batch: PrepareBatchUseCase
    process_batch_file: ProcessBatchFileUseCase
    finalize_batch: FinalizeBatchUseCase
    refresh_cases: RefreshBatchCasesUseCase
    queue_batch_file_clinical: QueueBatchFileClinicalUseCase
    materialize_batch_file: MaterializeBatchFileUseCase
    get_batch_status: GetBatchStatusUseCase
    list_user_batches: ListUserBatchesUseCase
    list_batch_files: ListBatchFilesUseCase
    list_pending_associations: ListPendingAssociationsUseCase
    list_batch_cases: ListBatchCasesUseCase
    queue_batch_epicrisis: QueueBatchEpicrisisUseCase
    queue_batch_epicrisis_excel: QueueBatchEpicrisisExcelUseCase
    generate_batch_epicrisis_excel: GenerateBatchEpicrisisExcelUseCase
    recompute_batch_bulk_epicrisis: RecomputeBatchBulkEpicrisisUseCase
    resolve_file_association: ResolveFileAssociationUseCase
    dispatcher_name: str


def build_batch_runtime(
    base_dir: Path,
    colombia_tz,
    *,
    clinical_document_service: ClinicalDocumentService,
    case_epicrisis_service: CaseEpicrisisService,
    mongo_database=None,
) -> BatchRuntime:
    """Compone dependencias del módulo batch sin contaminar el flujo legado."""

    batch_repository = MongoBatchRepository(database=mongo_database)
    batch_file_repository = MongoBatchFileRepository(database=mongo_database)
    batch_case_repository = MongoBatchCaseRepository(database=mongo_database)
    archive_store = LocalBatchArchiveStore(base_dir)
    archive_extractor = SafeZipArchiveExtractor(base_dir)
    artifact_cleaner = LocalBatchArtifactCleaner(base_dir)
    working_file_store = LocalBatchWorkingFileStore(base_dir)
    report_store = LocalBatchExcelReportStore(base_dir)
    text_extractor = PdfTextExtractor()
    prefactura_pdf_extractor = PyPdfPrefacturaExtractor()
    classifier = HeuristicDocumentClassifier()
    association_service = HeuristicCaseAssociationService()
    workbook_builder = BatchEpicrisisExcelWorkbookBuilder()

    totals_use_case = RecomputeBatchTotalsUseCase(
        batch_repository=batch_repository,
        batch_file_repository=batch_file_repository,
        colombia_tz=colombia_tz,
    )
    refresh_cases = RefreshBatchCasesUseCase(
        batch_repository=batch_repository,
        batch_file_repository=batch_file_repository,
        batch_case_repository=batch_case_repository,
    )
    prepare_batch = PrepareBatchUseCase(
        batch_repository=batch_repository,
        batch_file_repository=batch_file_repository,
        archive_extractor=archive_extractor,
        artifact_cleaner=artifact_cleaner,
        totals_use_case=totals_use_case,
        colombia_tz=colombia_tz,
    )
    process_batch_file = ProcessBatchFileUseCase(
        batch_file_repository=batch_file_repository,
        text_extractor=text_extractor,
        document_classifier=classifier,
        association_service=association_service,
        colombia_tz=colombia_tz,
    )
    finalize_batch = FinalizeBatchUseCase(
        batch_repository=batch_repository,
        batch_file_repository=batch_file_repository,
        association_service=association_service,
        totals_use_case=totals_use_case,
        refresh_cases_use_case=refresh_cases,
        colombia_tz=colombia_tz,
    )
    queue_batch_file_clinical = QueueBatchFileClinicalUseCase(
        batch_file_repository=batch_file_repository,
        totals_use_case=totals_use_case,
        refresh_cases_use_case=refresh_cases,
        colombia_tz=colombia_tz,
    )
    materialize_batch_file = MaterializeBatchFileUseCase(
        batch_repository=batch_repository,
        batch_file_repository=batch_file_repository,
        totals_use_case=totals_use_case,
        refresh_cases_use_case=refresh_cases,
        clinical_document_service=clinical_document_service,
        artifact_cleaner=artifact_cleaner,
        colombia_tz=colombia_tz,
    )
    recompute_batch_bulk_epicrisis = RecomputeBatchBulkEpicrisisUseCase(
        batch_repository=batch_repository,
        batch_case_repository=batch_case_repository,
    )
    queue_batch_epicrisis = QueueBatchEpicrisisUseCase(
        batch_repository=batch_repository,
        batch_case_repository=batch_case_repository,
        recompute_bulk_epicrisis_use_case=recompute_batch_bulk_epicrisis,
        colombia_tz=colombia_tz,
    )
    queue_batch_epicrisis_excel = QueueBatchEpicrisisExcelUseCase(
        batch_repository=batch_repository,
        batch_case_repository=batch_case_repository,
        colombia_tz=colombia_tz,
    )
    generate_batch_epicrisis_excel = GenerateBatchEpicrisisExcelUseCase(
        batch_repository=batch_repository,
        batch_case_repository=batch_case_repository,
        report_store=report_store,
        workbook_builder=workbook_builder,
        case_epicrisis_service=case_epicrisis_service,
        colombia_tz=colombia_tz,
    )

    def run_materialize_batch_file(batch_id: str, file_id: str) -> None:
        materialize_batch_file.execute(batch_id, file_id)

    dispatcher_mode = os.getenv("BATCH_DISPATCHER", "inprocess")
    dispatcher_mode = dispatcher_mode.strip().lower()
    if dispatcher_mode == "celery":
        dispatcher = CeleryBatchJobDispatcher()
    else:
        dispatcher = InProcessBatchJobDispatcher(
            prepare_runner=prepare_batch.execute,
            file_runner=process_batch_file.execute,
            finalize_runner=finalize_batch.execute,
            queue_materialize_runner=queue_batch_file_clinical.execute,
            materialize_runner=run_materialize_batch_file,
        )
        dispatcher_mode = "inprocess"

    create_batch_upload = CreateBatchUploadUseCase(
        batch_repository=batch_repository,
        archive_store=archive_store,
        job_dispatcher=dispatcher,
        colombia_tz=colombia_tz,
    )
    create_manual_batch_upload = CreateManualBatchUploadUseCase(
        batch_repository=batch_repository,
        batch_file_repository=batch_file_repository,
        working_file_store=working_file_store,
        job_dispatcher=dispatcher,
        colombia_tz=colombia_tz,
        case_context_resolver=clinical_document_service.get_user_case_context,
    )
    create_prefactura_batch_upload = CreatePrefacturaBatchUploadUseCase(
        batch_repository=batch_repository,
        batch_file_repository=batch_file_repository,
        working_file_store=working_file_store,
        prefactura_pdf_extractor=prefactura_pdf_extractor,
        document_classifier=classifier,
        association_service=association_service,
        job_dispatcher=dispatcher,
        colombia_tz=colombia_tz,
    )
    get_batch_status = GetBatchStatusUseCase(
        batch_repository=batch_repository,
        recompute_bulk_epicrisis_use_case=recompute_batch_bulk_epicrisis,
    )
    list_user_batches = ListUserBatchesUseCase(batch_repository=batch_repository)
    list_batch_files = ListBatchFilesUseCase(
        batch_file_repository=batch_file_repository
    )
    list_pending_associations = ListPendingAssociationsUseCase(
        batch_file_repository=batch_file_repository
    )
    list_batch_cases = ListBatchCasesUseCase(
        batch_case_repository=batch_case_repository
    )
    resolve_file_association = ResolveFileAssociationUseCase(
        batch_file_repository=batch_file_repository,
        totals_use_case=totals_use_case,
        refresh_cases_use_case=refresh_cases,
        colombia_tz=colombia_tz,
    )

    return BatchRuntime(
        create_batch_upload=create_batch_upload,
        create_manual_batch_upload=create_manual_batch_upload,
        create_prefactura_batch_upload=create_prefactura_batch_upload,
        prepare_batch=prepare_batch,
        process_batch_file=process_batch_file,
        finalize_batch=finalize_batch,
        refresh_cases=refresh_cases,
        queue_batch_file_clinical=queue_batch_file_clinical,
        materialize_batch_file=materialize_batch_file,
        get_batch_status=get_batch_status,
        list_user_batches=list_user_batches,
        list_batch_files=list_batch_files,
        list_pending_associations=list_pending_associations,
        list_batch_cases=list_batch_cases,
        queue_batch_epicrisis=queue_batch_epicrisis,
        queue_batch_epicrisis_excel=queue_batch_epicrisis_excel,
        generate_batch_epicrisis_excel=generate_batch_epicrisis_excel,
        recompute_batch_bulk_epicrisis=recompute_batch_bulk_epicrisis,
        resolve_file_association=resolve_file_association,
        dispatcher_name=dispatcher_mode,
    )
