"""
Brain Routing Receipts - Audit trail for brain routing decisions.

This module captures the routing decision at the moment it happens,
before execution. It's complementary to RouteOutcomeReceipt which
captures what actually happened after execution.

The flow:
1. route_decision() called -> BrainRoutingReceipt emitted (this module)
2. Brain executes the task
3. Outcome measured -> RouteOutcomeReceipt emitted (route_outcome.py)

---
feature:
  id: feature.brain_routing_receipts
  name: Brain Routing Domain Receipts
  kind: module
  summary: Receipt models for brain routing decisions at decision time
  owners: ["@codex"]
  stage: production
  tags: [receipts, routing, brain, episode, p0]
  depends_on: [feature.receipt_writer, feature.cloud_brain_router]
  inputs: [DecisionEnvelope, BrainChoice]
  outputs: [Signed receipts in ledger]
  invariants:
    - Every routing decision emits a receipt
    - Episode linkage enables traceability
    - Profile enforcement is always recorded
  risk_axes:
    missing_routing: 0.01
    profile_bypass: 0.0
---
"""

from __future__ import annotations

import logging
from typing import List, Optional

from pydantic import Field

from receipts.base import BaseReceipt

logger = logging.getLogger(__name__)


class BrainRoutingReceipt(BaseReceipt):
    """
    Receipt for a brain routing decision.

    Emitted every time cloud_brain_router.route_decision() is called.
    This captures the decision at routing time, before execution.

    Use RouteOutcomeReceipt (route_outcome.py) to capture actual outcomes.
    """
    receipt_type: str = Field(default="BrainRoutingReceipt", alias="type")
    domain: str = Field(default="brain_routing")

    # Episode linkage (CRITICAL for tracing)
    episode_id: Optional[str] = Field(
        default=None,
        description="Episode this routing belongs to (if known)"
    )

    # Routing decision identifiers
    envelope_id: str = Field(description="DecisionEnvelope being routed")
    route_id: str = Field(description="Unique ID for this routing decision")

    # Classification output
    risk_level: str = Field(
        description="LOW | MEDIUM | HIGH from classifier"
    )
    complexity: str = Field(
        description="TRIVIAL | SIMPLE | MODERATE | COMPLEX from classifier"
    )
    task_type: str = Field(
        description="CLASSIFICATION | CODE | REASONING | PLANNING | REFLEX"
    )

    # Brain selection
    live_brain: str = Field(
        description="Primary brain role: cloud_a | cloud_b | cloud_c | mlx"
    )
    shadow_brains: List[str] = Field(
        default_factory=list,
        description="Shadow brains for comparison"
    )

    # Classification metrics
    classification_latency_ms: float = Field(
        ge=0.0,
        description="Time to classify the request (ms)"
    )
    classifier_confidence: float = Field(
        ge=0.0, le=1.0,
        description="Classifier confidence: 0.5=heuristic, 0.8=mlx"
    )
    classification_source: str = Field(
        default="heuristic",
        description="mlx | heuristic | fallback"
    )

    # Provider specs (what was selected)
    live_provider: str = Field(
        description="Provider for live brain: anthropic | groq | mistral | mlx"
    )
    live_model: str = Field(
        description="Model selected for execution"
    )
    estimated_cost_usd: Optional[float] = Field(
        default=None,
        ge=0.0,
        description="Estimated cost for this request"
    )
    estimated_latency_ms: Optional[float] = Field(
        default=None,
        ge=0.0,
        description="Estimated latency for this request"
    )

    # Routing reason (human-readable)
    routing_reason: str = Field(
        description="Why this brain was chosen"
    )

    # Profile enforcement (THE CONSCIENCE GATE)
    deployment_profile: str = Field(
        description="Active profile name (Personal, Clinical, Airgapped, etc.)"
    )
    was_blocked_by_profile: bool = Field(
        default=False,
        description="True if ideal choice was blocked by profile"
    )
    original_choice: Optional[str] = Field(
        default=None,
        description="What we wanted before profile blocked it"
    )
    is_refusal: bool = Field(
        default=False,
        description="True if routing was refused entirely"
    )
    refusal_reason: Optional[str] = Field(
        default=None,
        description="Why routing was refused"
    )

    # Intent context (truncated for privacy)
    intent_hash: Optional[str] = Field(
        default=None,
        description="SHA256 hash of intent (first 16 chars)"
    )
    intent_domain: str = Field(
        default="general",
        description="Domain hint: code | browser | file | general"
    )
    intent_length: Optional[int] = Field(
        default=None,
        ge=0,
        description="Length of intent in characters"
    )


class EpisodeRoutingSummary(BaseReceipt):
    """
    Summary of all routing decisions within an episode.

    Emitted when an episode ends to provide aggregate view.
    """
    receipt_type: str = Field(default="EpisodeRoutingSummary", alias="type")
    domain: str = Field(default="brain_routing")

    # Episode identification
    episode_id: str = Field(description="Episode this summary is for")

    # Aggregate counts
    total_routes: int = Field(
        ge=0,
        description="Total routing decisions in this episode"
    )
    routes_to_cloud_a: int = Field(default=0, ge=0)
    routes_to_cloud_b: int = Field(default=0, ge=0)
    routes_to_cloud_c: int = Field(default=0, ge=0)
    routes_to_mlx: int = Field(default=0, ge=0)

    # Profile enforcement summary
    profile_blocks: int = Field(
        default=0, ge=0,
        description="How many routes were blocked by profile"
    )
    refusals: int = Field(
        default=0, ge=0,
        description="How many routes were refused entirely"
    )

    # Performance
    total_classification_time_ms: float = Field(
        default=0.0, ge=0.0,
        description="Sum of classification latencies"
    )
    avg_classifier_confidence: float = Field(
        default=0.5,
        ge=0.0, le=1.0,
        description="Average classifier confidence"
    )

    # Route IDs for tracing
    route_ids: List[str] = Field(
        default_factory=list,
        description="All routing receipt IDs in this episode"
    )
