"""Deterministic routing engine for Intelligence Pipeline v3.

The RoutingEngine combines hard ambiguity/conflict rules with calibrated
confidence thresholds to produce a deterministic route decision. The same
inputs always produce the same output — no randomness or side effects.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any
from uuid import UUID, uuid4

from services.intelligence_pipeline_v3.routing.reasons import (
    RouteDecision,
    RoutingReason,
)
from services.intelligence_pipeline_v3.routing.rules import evaluate_hard_rules
from services.intelligence_pipeline_v3.routing.thresholds import (
    FastPathThresholds,
    evaluate_thresholds,
)


@dataclass(frozen=True)
class RoutingDecision:
    """Immutable record of a routing decision with full context.

    Attributes
    ----------
    id:
        Unique identifier for this decision.
    pipeline_run_id:
        The pipeline run this decision belongs to.
    document_id:
        The document being routed.
    route:
        The binary routing outcome (fast_path or adjudication).
    reasons:
        List of routing reasons explaining the decision.
    confidence_snapshot:
        Full feature snapshot at decision time for audit and recalibration.
    decided_at:
        UTC timestamp of the decision.
    """

    id: UUID
    pipeline_run_id: UUID
    document_id: UUID
    route: RouteDecision
    reasons: list[RoutingReason]
    confidence_snapshot: dict[str, Any]
    decided_at: datetime


@dataclass
class RoutingEngine:
    """Deterministic routing engine.

    Evaluates hard rules first, then applies confidence thresholds.
    Same inputs always produce the same route — no randomness, no external
    state dependency beyond the provided arguments.

    Parameters
    ----------
    thresholds:
        Fast-path threshold configuration. Defaults to conservative values.
    """

    thresholds: FastPathThresholds = field(default_factory=FastPathThresholds)

    def route(
        self,
        pipeline_run_id: UUID,
        document_id: UUID,
        confidence_features: dict[str, Any],
        ambiguity_markers: dict[str, Any],
        document_type: str,
        event_type: str | None = None,
    ) -> RoutingDecision:
        """Produce a deterministic routing decision.

        Parameters
        ----------
        pipeline_run_id:
            The pipeline run identifier.
        document_id:
            The document being routed.
        confidence_features:
            Field-level confidence features from the confidence pipeline.
            Must include ``calibrated_confidence`` (float 0-1).
        ambiguity_markers:
            Structural ambiguity markers from candidate generation.
        document_type:
            The document type (article, filing, transcript, etc.).
        event_type:
            Optional event type detected in the document.

        Returns
        -------
        RoutingDecision
            Immutable decision record with route, reasons, and feature snapshot.
        """
        # Step 1: Evaluate hard rules (any trigger = adjudication)
        hard_reasons = evaluate_hard_rules(confidence_features, ambiguity_markers)

        if hard_reasons:
            return self._build_decision(
                pipeline_run_id=pipeline_run_id,
                document_id=document_id,
                route=RouteDecision.ADJUDICATION,
                reasons=hard_reasons,
                confidence_features=confidence_features,
                ambiguity_markers=ambiguity_markers,
            )

        # Step 2: Evaluate confidence thresholds
        calibrated_confidence = confidence_features.get("calibrated_confidence", 0.0)

        # Check evidence coverage threshold (hard threshold, not configurable per doc type)
        evidence_coverage = confidence_features.get("evidence_coverage", 1.0)
        if evidence_coverage < 0.5:
            return self._build_decision(
                pipeline_run_id=pipeline_run_id,
                document_id=document_id,
                route=RouteDecision.ADJUDICATION,
                reasons=[RoutingReason.EVIDENCE_COVERAGE_BELOW_THRESHOLD],
                confidence_features=confidence_features,
                ambiguity_markers=ambiguity_markers,
            )

        # Apply calibrated confidence threshold
        threshold_decision = evaluate_thresholds(
            confidence=calibrated_confidence,
            document_type=document_type,
            event_type=event_type,
            thresholds=self.thresholds,
        )

        if threshold_decision == RouteDecision.ADJUDICATION:
            return self._build_decision(
                pipeline_run_id=pipeline_run_id,
                document_id=document_id,
                route=RouteDecision.ADJUDICATION,
                reasons=[RoutingReason.CALIBRATED_CONFIDENCE_BELOW_THRESHOLD],
                confidence_features=confidence_features,
                ambiguity_markers=ambiguity_markers,
            )

        # All checks passed — fast path accepted
        return self._build_decision(
            pipeline_run_id=pipeline_run_id,
            document_id=document_id,
            route=RouteDecision.FAST_PATH,
            reasons=[RoutingReason.FAST_PATH_ACCEPTED],
            confidence_features=confidence_features,
            ambiguity_markers=ambiguity_markers,
        )

    def _build_decision(
        self,
        pipeline_run_id: UUID,
        document_id: UUID,
        route: RouteDecision,
        reasons: list[RoutingReason],
        confidence_features: dict[str, Any],
        ambiguity_markers: dict[str, Any],
    ) -> RoutingDecision:
        """Build an immutable routing decision with full snapshot."""
        return RoutingDecision(
            id=uuid4(),
            pipeline_run_id=pipeline_run_id,
            document_id=document_id,
            route=route,
            reasons=reasons,
            confidence_snapshot={
                "confidence_features": confidence_features,
                "ambiguity_markers": ambiguity_markers,
                "thresholds_version": self.thresholds.version,
            },
            decided_at=datetime.now(timezone.utc),
        )
