"""
Transport Policy Registry for Tool-MoE-Receipts Architecture

WO-MODULAR-INVENTORY-01: Centralizes transport mode definitions and routing policies.

This registry maps transport modes to their:
- Tool configurations
- Receipt types
- Routing policies
- Schema versions

Usage:
    from helix_cdc.echo.ops.transport_policy import (
        TransportMode,
        TRANSPORT_POLICIES,
        get_policy,
        ROUTER_SCHEMA_VERSION,
    )

    policy = get_policy(TransportMode.GEOMETRY_ROUTED)
    print(policy.tool_name)  # "fibpi3d_spatial_tool"
"""

from dataclasses import dataclass
from enum import Enum
from typing import Any, Dict, Optional, List


# Router schema version for forward compatibility
# Increment minor version for additive changes, major for breaking changes
ROUTER_SCHEMA_VERSION = "1.0.0"


class TransportMode(str, Enum):
    """
    Transport modes for routing decisions.

    Each mode represents a distinct path through the system:
    - Tool-routed modes bypass LLM and go directly to specialized tools
    - LLM modes go through the language model backend
    """
    # Uncertainty dispatch (WO-ECHO-UNCERTAINTY-DISPATCH) - checked FIRST
    UNCERTAINTY_DISPATCH = "uncertainty_dispatch"

    # Tool-routed modes (bypass LLM)
    GEOMETRY_ROUTED = "geometry_routed"
    MATH_ROUTED = "math_routed"
    RETRIEVAL_ROUTED = "retrieval_routed"
    CODE_ROUTED = "code_routed"
    TEST_ROUTED = "test_routed"  # WO-ECHO-TEST-AGENT-01
    PATCH_ROUTED = "patch_routed"  # WO-ECHO-PATCH-AGENT-01
    PLAN_ROUTED = "plan_routed"  # WO-ECHO-PLAN-AGENT-01

    # LLM modes
    LLM_ROUTED = "llm_routed"
    BASIN_CHAT = "basin_chat"

    # Special modes
    MOCK = "mock"
    STREAMING = "streaming"
    HELIXCODE = "helixcode"


class ReceiptType(str, Enum):
    """Receipt types for different transport modes."""
    ECHO_LOOP = "echo_loop"           # Full Echo->Tool->Echo loop receipt
    BASIN_CHAT = "basin_chat"         # Chat completion receipt
    STREAMING = "streaming_receipt"   # CDNAv2 streaming receipt
    HELIXCODE = "helixcode_receipt"   # HelixCode decode receipt
    MOCK = "mock_receipt"             # Mock/test receipt
    NONE = "none"                     # No receipt


@dataclass(frozen=True)
class TransportPolicy:
    """
    Policy configuration for a transport mode.

    Attributes:
        mode: The transport mode this policy applies to
        tool_name: Name of the tool to route to (None for LLM modes)
        receipt_type: Type of receipt to emit
        intent_detector: Function name used for detection (e.g., "detect_geometry_intent")
        work_order: Associated work order for tracking
        requires_llm: Whether this mode requires LLM backend
        priority: Routing priority (lower = higher priority, checked first)
        confidence_threshold: Minimum confidence to trigger this route
    """
    mode: TransportMode
    tool_name: Optional[str]
    receipt_type: ReceiptType
    intent_detector: Optional[str]
    work_order: str
    requires_llm: bool
    priority: int
    confidence_threshold: float = 0.0


# Transport policy registry
# Policies are checked in priority order (lower number = checked first)
TRANSPORT_POLICIES: Dict[TransportMode, TransportPolicy] = {
    # WO-ECHO-UNCERTAINTY-DISPATCH: Uncertainty dispatch checked FIRST (priority 5)
    # Triggers when explicit lookup markers OR all other detectors have low confidence
    TransportMode.UNCERTAINTY_DISPATCH: TransportPolicy(
        mode=TransportMode.UNCERTAINTY_DISPATCH,
        tool_name="uncertainty_dispatcher",
        receipt_type=ReceiptType.ECHO_LOOP,
        intent_detector="detect_uncertainty_intent",
        work_order="WO-ECHO-UNCERTAINTY-DISPATCH",
        requires_llm=False,
        priority=5,  # Check FIRST before specific tools
        confidence_threshold=0.0,
    ),
    TransportMode.GEOMETRY_ROUTED: TransportPolicy(
        mode=TransportMode.GEOMETRY_ROUTED,
        tool_name="fibpi3d_spatial_tool",
        receipt_type=ReceiptType.ECHO_LOOP,
        intent_detector="detect_geometry_intent",
        work_order="WO-ECHO-FIBPI3D-LOOP-02",
        requires_llm=False,
        priority=10,
        confidence_threshold=0.0,  # Any match triggers
    ),
    TransportMode.MATH_ROUTED: TransportPolicy(
        mode=TransportMode.MATH_ROUTED,
        tool_name="calculator_tool",
        receipt_type=ReceiptType.ECHO_LOOP,
        intent_detector="detect_math_intent",
        work_order="WO-MODULAR-INVENTORY-01",
        requires_llm=False,
        priority=20,
        confidence_threshold=0.0,
    ),
    TransportMode.RETRIEVAL_ROUTED: TransportPolicy(
        mode=TransportMode.RETRIEVAL_ROUTED,
        tool_name="retrieval_tool",
        receipt_type=ReceiptType.ECHO_LOOP,
        intent_detector="detect_retrieval_intent",
        work_order="WO-MODULAR-INVENTORY-01",
        requires_llm=False,
        priority=30,
        confidence_threshold=0.0,
    ),
    TransportMode.CODE_ROUTED: TransportPolicy(
        mode=TransportMode.CODE_ROUTED,
        tool_name="code_executor_tool",
        receipt_type=ReceiptType.ECHO_LOOP,
        intent_detector="detect_code_intent",
        work_order="WO-MODULAR-INVENTORY-01",
        requires_llm=False,
        priority=40,
        confidence_threshold=0.0,
    ),
    # WO-ECHO-TEST-AGENT-01: Test execution routing
    # High-intent commands should preempt geometry/math routing
    TransportMode.TEST_ROUTED: TransportPolicy(
        mode=TransportMode.TEST_ROUTED,
        tool_name="test_agent",
        receipt_type=ReceiptType.ECHO_LOOP,
        intent_detector="detect_test_intent",
        work_order="WO-ECHO-TEST-AGENT-01",
        requires_llm=False,
        priority=7,  # After uncertainty (5), before geometry (10)
        confidence_threshold=0.0,
    ),
    # WO-ECHO-PATCH-AGENT-01: Patch/edit routing with pre/post test gates
    TransportMode.PATCH_ROUTED: TransportPolicy(
        mode=TransportMode.PATCH_ROUTED,
        tool_name="patch_agent",
        receipt_type=ReceiptType.ECHO_LOOP,
        intent_detector="detect_patch_intent",
        work_order="WO-ECHO-PATCH-AGENT-01",
        requires_llm=False,
        priority=12,  # After geometry (10), patches are less common
        confidence_threshold=0.0,
    ),
    # WO-ECHO-PLAN-AGENT-01: Plan/work order generation before execution
    TransportMode.PLAN_ROUTED: TransportPolicy(
        mode=TransportMode.PLAN_ROUTED,
        tool_name="plan_agent",
        receipt_type=ReceiptType.ECHO_LOOP,
        intent_detector="detect_plan_intent",
        work_order="WO-ECHO-PLAN-AGENT-01",
        requires_llm=False,
        priority=6,  # After uncertainty (5), before test (7) - planning should happen early
        confidence_threshold=0.0,
    ),
    TransportMode.LLM_ROUTED: TransportPolicy(
        mode=TransportMode.LLM_ROUTED,
        tool_name=None,
        receipt_type=ReceiptType.BASIN_CHAT,
        intent_detector=None,
        work_order="WO-BASIN-RECEIPTS-CHAT-01",
        requires_llm=True,
        priority=100,  # Fallback
        confidence_threshold=0.0,
    ),
    TransportMode.BASIN_CHAT: TransportPolicy(
        mode=TransportMode.BASIN_CHAT,
        tool_name=None,
        receipt_type=ReceiptType.BASIN_CHAT,
        intent_detector=None,
        work_order="WO-BASIN-RECEIPTS-CHAT-01",
        requires_llm=True,
        priority=100,
        confidence_threshold=0.0,
    ),
    TransportMode.MOCK: TransportPolicy(
        mode=TransportMode.MOCK,
        tool_name=None,
        receipt_type=ReceiptType.MOCK,
        intent_detector=None,
        work_order="TEST",
        requires_llm=False,
        priority=200,
        confidence_threshold=0.0,
    ),
    TransportMode.STREAMING: TransportPolicy(
        mode=TransportMode.STREAMING,
        tool_name=None,
        receipt_type=ReceiptType.STREAMING,
        intent_detector=None,
        work_order="WO-CDNA-V2-ATTN-STREAMING",
        requires_llm=False,
        priority=50,
        confidence_threshold=0.0,
    ),
    TransportMode.HELIXCODE: TransportPolicy(
        mode=TransportMode.HELIXCODE,
        tool_name=None,
        receipt_type=ReceiptType.HELIXCODE,
        intent_detector=None,
        work_order="WO-HELIX-DECODE-BLOCK-01",
        requires_llm=False,
        priority=50,
        confidence_threshold=0.0,
    ),
}


def get_policy(mode: TransportMode) -> TransportPolicy:
    """
    Get the transport policy for a given mode.

    Args:
        mode: The transport mode

    Returns:
        TransportPolicy for the mode

    Raises:
        KeyError: If mode is not registered
    """
    return TRANSPORT_POLICIES[mode]


def get_tool_routed_policies() -> List[TransportPolicy]:
    """
    Get all policies that route to tools (not LLM).

    Returns:
        List of TransportPolicy objects sorted by priority
    """
    return sorted(
        [p for p in TRANSPORT_POLICIES.values() if p.tool_name is not None],
        key=lambda p: p.priority
    )


def get_mode_by_tool(tool_name: str) -> Optional[TransportMode]:
    """
    Get the transport mode for a given tool name.

    Args:
        tool_name: Name of the tool

    Returns:
        TransportMode or None if not found
    """
    for policy in TRANSPORT_POLICIES.values():
        if policy.tool_name == tool_name:
            return policy.mode
    return None


def build_router_metadata(
    mode: TransportMode,
    router_decision: Dict[str, Any],
    extra: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    """
    Build standardized router metadata for response.

    Args:
        mode: Transport mode used
        router_decision: Decision dict from intent detector
        extra: Additional metadata to include

    Returns:
        Dict with transport_mode, router_decision, router_schema_version, and any extra fields
    """
    policy = TRANSPORT_POLICIES.get(mode)
    metadata = {
        "transport_mode": mode.value,
        "router_decision": router_decision,
        "router_schema_version": ROUTER_SCHEMA_VERSION,
    }

    if policy:
        metadata["work_order"] = policy.work_order
        metadata["tool_name"] = policy.tool_name
        metadata["receipt_type"] = policy.receipt_type.value

    if extra:
        metadata.update(extra)

    return metadata


# Exported for convenience
__all__ = [
    "TransportMode",
    "TransportPolicy",
    "ReceiptType",
    "TRANSPORT_POLICIES",
    "ROUTER_SCHEMA_VERSION",
    "get_policy",
    "get_tool_routed_policies",
    "get_mode_by_tool",
    "build_router_metadata",
]
