"""All Pydantic models and enums."""

from __future__ import annotations

from enum import Enum
from uuid import uuid4

from pydantic import BaseModel, Field

# ============================================================
# Enums
# ============================================================


class InputType(str, Enum):
    REPORT = "report"
    INTERVIEW = "interview"
    REFLECTION = "reflection"
    IDEA = "idea"


class Sensitivity(str, Enum):
    NORMAL = "normal"
    PRIVATE = "private"


class RoutingPolicy(str, Enum):
    NONE = "none"
    RECOMMEND = "recommend"
    REQUIRED = "required"


class SceneType(str, Enum):
    EXPLAIN = "explain"
    CRITIQUE = "critique"
    DESIGN = "design"
    DECISION = "decision"
    INTERVIEW_FOLLOWUP = "interview_followup"
    POSTMORTEM = "postmortem"


class InsightType(str, Enum):
    STRUCTURING_GAP = "structuring_gap"
    FAILURE_MODE_GAP = "failure_mode_gap"
    TRADEOFF_GAP = "tradeoff_gap"
    METRIC_GAP = "metric_gap"
    EXAMPLE_GAP = "example_gap"
    ASSUMPTION_GAP = "assumption_gap"


# ============================================================
# Tagger models
# ============================================================


class Tags(BaseModel):
    topics: list[str]
    domains: list[str]
    difficulty: int = Field(ge=1, le=5)
    sensitivity: Sensitivity = Sensitivity.NORMAL


class CapabilityMap(BaseModel):
    concept_understanding: int = Field(ge=0, le=10)
    structuring: int = Field(ge=0, le=10)
    tradeoff_thinking: int = Field(ge=0, le=10)
    system_thinking: int = Field(ge=0, le=10)
    communication: int = Field(ge=0, le=10)


class PracticeSeed(BaseModel):
    preferred_scene: SceneType
    skills: list[str]
    concepts: list[str]
    constraints: list[str]


class TaggerOutput(BaseModel):
    input_type: InputType
    summary: str
    tags: Tags
    capability_map: CapabilityMap
    routing_policy: RoutingPolicy
    practice_seed: PracticeSeed


# ============================================================
# Practice models
# ============================================================


class PracticeSceneLLM(BaseModel):
    """Schema sent to LLM (no scene_id; generated by app)."""

    scene_type: SceneType
    role: str
    task: str
    constraints: list[str]
    rubric: list[str]
    expected_structure_hint: list[str]


class PracticeScene(BaseModel):
    """Full scene model (with scene_id)."""

    scene_id: str = Field(default_factory=lambda: str(uuid4()))
    scene_type: SceneType
    role: str
    task: str
    constraints: list[str]
    rubric: list[str]
    expected_structure_hint: list[str]


class PracticeMessage(BaseModel):
    """Single message in a multi-turn practice conversation."""

    role: str  # "coach" or "user"
    content: str


class CoachReply(BaseModel):
    """Structured output from the coach LLM each turn."""

    message: str
    ready_for_evaluation: bool = Field(
        description="True when the coach decides the conversation has enough "
        "material to hand off to the evaluator.",
    )


class PerformanceSignal(BaseModel):
    clarity: int = Field(ge=0, le=10)
    reasoning_depth: int = Field(ge=0, le=10)
    decision_quality: int = Field(ge=0, le=10)
    communication: int = Field(ge=0, le=10)


class PracticePerformance(BaseModel):
    performance_signal: PerformanceSignal
    improvement_vectors: list[str]


# ============================================================
# Insight models
# ============================================================


class InsightCard(BaseModel):
    insight_title: str
    insight_type: InsightType
    what_happened: str
    why_it_matters: str
    upgrade_pattern: str
    micro_practice: str
    concepts: list[str]
    skills: list[str]
    scenes: list[str]  # linked scene_ids
    intensity: int = Field(ge=1, le=5)


class InsightList(BaseModel):
    """Wrapper model returned by LLM (OpenAI structured output requires top-level object)."""

    cards: list[InsightCard]
