"""EligibilityPipeline — two-phase eligibility validation orchestrator.

Delegates rule-based validation to ``BasePipeline``. AI interpretation
remains domain-specific (uses ``interpret()`` not ``validate_deidentified()``).
"""

from __future__ import annotations

import time
from typing import TYPE_CHECKING

from claim_validator.conf import ClaimValidatorSettings
from claim_validator.constants import Severity
from claim_validator.eligibility.models.result import EligibilityResult
from claim_validator.exceptions import LLMError
from claim_validator.models.results import Finding
from claim_validator.shared.pipeline.config import PipelineConfig
from claim_validator.shared.pipeline.context import ValidationContext
from claim_validator.shared.pipeline.engine import BasePipeline
from claim_validator.validators.registry import ValidatorRegistry

if TYPE_CHECKING:
    from claim_validator.eligibility.models.request import EligibilityRequest
    from claim_validator.eligibility.models.response import EligibilityResponse
    from claim_validator.eligibility.validators.ai.interpreter import (
        EligibilityInterpreterAI,
    )
    from claim_validator.validators.base import BaseValidator


_SEVERITY_ORDER: dict[Severity, int] = {Severity.ERROR: 0, Severity.WARNING: 1}


class EligibilityPipeline:
    """Two-phase eligibility validation pipeline.

    Phase 1: Rule-based validators (delegated to BasePipeline)
    Phase 2: AI interpretation (requires LLM config + eligibility response)
    """

    def __init__(
        self,
        *,
        rule_validators: list[BaseValidator],
        ai_interpreter: EligibilityInterpreterAI | None = None,
        skip_ai_on_rule_failure: bool = True,
    ) -> None:
        self._rule_validators = rule_validators
        self._ai_interpreter = ai_interpreter
        self._skip_ai_on_rule_failure = skip_ai_on_rule_failure
        self._base_pipeline = BasePipeline(
            PipelineConfig(
                domain="eligibility",
                validators=tuple(rule_validators),
                code_prefix="",  # validators add ELIG_ prefix themselves
            )
        )

    @classmethod
    def from_settings(
        cls,
        settings: ClaimValidatorSettings | None = None,
    ) -> EligibilityPipeline:
        """Create a pipeline from settings."""
        if settings is None:
            settings = ClaimValidatorSettings()
        registry = ValidatorRegistry()
        rule_vals = registry.create_validators(
            settings.eligibility_rule_validators,
        )

        ai_interpreter = None
        if not settings.eligibility_skip_ai:
            provider_cfg = settings.get_provider_config("eligibility_interpreter")
            ai_config = (
                provider_cfg.model_dump() if provider_cfg is not None
                and not isinstance(provider_cfg, dict)
                else provider_cfg
            ) or settings.ai_config
            if ai_config:
                from claim_validator.chains.eligibility_interpreter import (
                    build_eligibility_interpreter_chain,
                )
                from claim_validator.eligibility.validators.ai.interpreter import (
                    EligibilityInterpreterAI,
                )

                chain = build_eligibility_interpreter_chain(ai_config)
                ai_interpreter = EligibilityInterpreterAI(
                    chain=chain,
                )

        return cls(
            rule_validators=rule_vals,
            ai_interpreter=ai_interpreter,
            skip_ai_on_rule_failure=settings.eligibility_skip_ai_on_rule_failure,
        )

    def run(
        self,
        request: EligibilityRequest,
        *,
        response: EligibilityResponse | None = None,
        validation_context: ValidationContext | None = None,
    ) -> EligibilityResult:
        """Execute the eligibility validation pipeline.

        Args:
            request: Eligibility request to validate.
            response: Optional pre-fetched eligibility response
                for AI interpretation.
            validation_context: Optional cross-stage validation context
                for passthrough optimization.
        """
        start = time.perf_counter()
        ai_summary: str | None = None

        # Phase 1: Delegate rule-based validation to BasePipeline
        rule_result = self._base_pipeline.run(
            request, validation_context=validation_context,
        )
        rule_phase = rule_result.phase_results[0]
        findings: list[Finding] = list(rule_phase.findings)

        # Phase 2: AI interpretation (if configured + response available)
        if self._ai_interpreter and response is not None:
            rule_has_errors = any(
                f.severity == Severity.ERROR for f in findings
            )
            if not rule_has_errors or not self._skip_ai_on_rule_failure:
                ai_summary, ai_findings = self._run_ai_phase(response)
                findings.extend(ai_findings)

        findings.sort(key=lambda f: _SEVERITY_ORDER.get(f.severity, 99))

        elapsed = time.perf_counter() - start
        return EligibilityResult(
            eligible=response.eligible if response else None,
            response=response,
            findings=findings,
            ai_summary=ai_summary,
            execution_time=elapsed,
        )

    def _run_ai_phase(
        self,
        response: EligibilityResponse,
    ) -> tuple[str | None, list[Finding]]:
        """De-identify response and run AI interpretation."""
        from claim_validator.eligibility.deidentifier import (
            EligibilityDeidentifier,
        )

        assert self._ai_interpreter is not None  # noqa: S101

        try:
            deidentified = EligibilityDeidentifier.deidentify(response)
            ai_summary, ai_findings = self._ai_interpreter.interpret(
                deidentified,
            )
            return ai_summary, ai_findings
        except LLMError as exc:
            return None, [
                Finding(
                    code="AI_ELIG_PROVIDER_ERROR",
                    message="AI interpretation unavailable",
                    severity=Severity.WARNING,
                    field_name="",
                    suggestion=(
                        "Rule-based results are still valid. "
                        "Retry when the AI provider is available."
                    ),
                    context={"error": str(exc)},
                ),
            ]
        except Exception as exc:
            return None, [
                Finding(
                    code="VALIDATOR_ERROR",
                    message="AI interpreter raised an unexpected exception",
                    severity=Severity.ERROR,
                    field_name="",
                    suggestion="Check AI interpreter implementation",
                    context={"error": str(exc)},
                ),
            ]
