"""
Pydantic models — the contract between every layer of the app.
"""

from __future__ import annotations
from pydantic import BaseModel, Field
from typing import Optional, List


# ═══════════════════════════════════════════════════════════════
# REQUEST MODELS
# ═══════════════════════════════════════════════════════════════

class GenerateRequest(BaseModel):
    stock_symbol: str = Field("", examples=["AAPL"])
    zscore_window: int = Field(default=100, ge=5)
    zscore_trigger_min: float = Field(default=-2.5)
    zscore_trigger_max: float = Field(default=2.5)
    knowledge_base_id: Optional[str] = None


class ChatRequest(BaseModel):
    session_id: str = Field(default="default")
    message: str
    knowledge_base_id: Optional[str] = None


# ═══════════════════════════════════════════════════════════════
# Z-SCORE MODELS
# ═══════════════════════════════════════════════════════════════

class ZScoreEvent(BaseModel):
    date: str
    price: float
    z_score: float
    event_type: str          # "major" | "normal"
    context: str
    direction: str           # "decline" | "rally"


class ZScoreResult(BaseModel):
    events: List[ZScoreEvent]
    total_events: int
    window_size: int
    data_points: int


# ═══════════════════════════════════════════════════════════════
# SCENARIO MODELS
# ═══════════════════════════════════════════════════════════════

class AnswerOption(BaseModel):
    answer: str
    explanation: str


class BestAnswer(BaseModel):
    answer: str
    rationale: str


class GivensTable(BaseModel):
    date: Optional[str] = None
    stock_symbol: Optional[str] = None
    price: Optional[float] = None
    z_score: Optional[float] = None
    event_type: Optional[str] = None
    market_conditions: Optional[str] = None
    context: Optional[str] = None

    class Config:
        extra = "allow"          # AI may add extra fields


class Scenario(BaseModel):
    id: str
    title: str
    short_description: str = Field(alias="shortDescription", default="")
    givens_table: GivensTable = Field(alias="givensTable")
    scenario_paragraph: str = Field(alias="scenarioParagraph", default="")
    best_answer: BestAnswer = Field(alias="bestAnswer", default_factory=lambda: BestAnswer(answer="Unknown", rationale="Unknown"))
    
    # Strictly padding exactly 3 elements to prevent IndexError during DB integration
    other_answers: list[AnswerOption] = Field(
        alias="otherAnswers", 
        default_factory=lambda: [
            AnswerOption(answer="Unknown A", explanation="TBD"),
            AnswerOption(answer="Unknown B", explanation="TBD"),
            AnswerOption(answer="Unknown C", explanation="TBD")
        ]
    )
    
    event_type: Optional[str] = None
    risk_level: str = Field(alias="riskLevel", description="Low, Medium, or High", default="Medium")

    class Config:
        populate_by_name = True


class ScenarioGenerationResult(BaseModel):
    scenarios: list[Scenario]
    total_possible_scenarios: int = Field(alias="totalPossibleScenarios")

    class Config:
        populate_by_name = True


# ═══════════════════════════════════════════════════════════════
# CHAT MODELS
# ═══════════════════════════════════════════════════════════════

class ChatResponse(BaseModel):
    session_id: str
    reply: str
