"""Factory helpers for leaudit's native service-layer orchestration.

This module is the bridge-side assembly point for native leaudit services:

- ``AuditServices``
- ``DocNormalizationService``
- ``ExtractionService``
- ``EvaluationService``
- ``RescueService``
- ``AuditService``

The platform should not construct these objects in controllers/services
directly. Keep all leaudit-native wiring inside ``leaudit_bridge/``.
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from leaudit.services.audit_service import AuditService
from leaudit.services.audit_services import AuditServices
from leaudit.services.doc_normalization_service import DocNormalizationService
from leaudit.services.evaluation_service import EvaluationService
from leaudit.services.extraction_service import ExtractionService
from leaudit.services.rescue_service import RescueService

from fastapi_admin.config import LEAUDIT_OCR_VLM_CONCURRENCY
from fastapi_modules.fastapi_leaudit.leaudit_bridge.client_factory import (
    create_llm_client,
    create_ocr_client,
    create_vlm_client,
)
from fastapi_modules.fastapi_leaudit.leaudit_bridge.ocr_bridge import BridgeOCRClient


@dataclass(frozen=True)
class NativeServiceBundle:
    """Fully assembled native leaudit service bundle."""

    audit_service: AuditService
    audit_services: AuditServices
    normalization_service: DocNormalizationService
    extraction_service: ExtractionService
    evaluation_service: EvaluationService
    rescue_service: RescueService | None


class AuditServiceFactory:
    """Build native leaudit services for one platform-side run."""

    def create_bundle(self, rules_path: str | None = None) -> NativeServiceBundle:
        """Create a fully wired native leaudit service bundle.

        ``rules_path`` is only used to force the normalization adapter's
        classification path when the caller wants a fixed rules file.
        """
        normalization_service, audit_services = self._create_normalization_services(
            rules_path=rules_path
        )
        extraction_service = ExtractionService(
            session=None,
            llm_client=audit_services.llm_client,
        )
        evaluation_service = EvaluationService(session=None)
        rescue_service = RescueService(
            session=None,
            llm_client=audit_services.llm_client,
            vlm_client=audit_services.vlm_client,
            extraction_service=extraction_service,
        )

        audit_service = AuditService(
            document_service=None,
            normalization_service=normalization_service,
            extraction_service=extraction_service,
            evaluation_service=evaluation_service,
            rescue_service=rescue_service,
            services=AuditServices(
                llm_client=audit_services.llm_client,
                vlm_client=audit_services.vlm_client,
                ocr_client=audit_services.ocr_client,
                normalization=normalization_service,
                extraction=extraction_service,
                evaluation=evaluation_service,
            ),
        )

        return NativeServiceBundle(
            audit_service=audit_service,
            audit_services=audit_service.services,
            normalization_service=normalization_service,
            extraction_service=extraction_service,
            evaluation_service=evaluation_service,
            rescue_service=rescue_service,
        )

    def _create_normalization_services(
        self, rules_path: str | None = None
    ) -> tuple[DocNormalizationService, AuditServices]:
        """Create normalization service plus low-level shared clients."""
        from leaudit.doc_normalization.adapter import DocNormalizationAdapter
        from leaudit.doc_normalization.doc_classifier import RulesFileRegistry

        raw_ocr = create_ocr_client()
        llm_client = create_llm_client()
        vlm_client = create_vlm_client()

        registry = None
        if rules_path is None:
            rules_dir = Path(__file__).resolve().parents[3] / "rules"
            if rules_dir.is_dir():
                registry = RulesFileRegistry.from_directory(rules_dir)

        adapter = DocNormalizationAdapter(
            ocr_client=raw_ocr,
            registry=registry,
            llm_client=llm_client,
            vlm_client=vlm_client,
            force_rules_path=rules_path,
        )
        ocr_client = BridgeOCRClient(
            adapter,
            vlm_client=vlm_client,
            vlm_concurrency=LEAUDIT_OCR_VLM_CONCURRENCY,
        )
        normalization_service = DocNormalizationService(ocr_client)
        audit_services = AuditServices(
            llm_client=llm_client,
            vlm_client=vlm_client,
            ocr_client=raw_ocr,
            normalization=normalization_service,
        )
        return normalization_service, audit_services


__all__ = ["AuditServiceFactory", "NativeServiceBundle"]
