# src/web/api/v2/schemas/calibration_strategies.py

from typing import Any, Dict, List, Literal, Optional, Union
from pydantic import BaseModel, Field

from .calibration_risk import StopConfigSchema, RiskConfigSchema, GlobalRiskRulesSchema


ParameterValue = Union[int, float, bool, str]


class WalkForwardConfigSchema(BaseModel):
    train_days: int = Field(..., gt=0)
    test_days: int = Field(..., gt=0)
    step_days: Optional[int] = Field(None, gt=0)
    min_trades_test: int = Field(10, ge=0)


class StrategySelectionSchema(BaseModel):
    strategy_id: str
    parameters: Dict[str, ParameterValue]


class CalibrationStrategiesInspectRequest(BaseModel):
    symbol: str
    timeframe: str

    # snapshot from Step 2 (closed)
    stop: StopConfigSchema
    risk: RiskConfigSchema
    global_rules: GlobalRiskRulesSchema
    account_equity: float = Field(..., gt=0)

    strategies: List[StrategySelectionSchema]
    wf: WalkForwardConfigSchema

    commission: float = Field(0.001, ge=0)
    slippage: float = Field(0.0005, ge=0)


class WindowRowSchema(BaseModel):
    window: int
    train_start: str
    train_end: str
    test_start: str
    test_end: str

    return_pct: float
    sharpe: float
    max_dd_pct: float
    trades: int
    params: Dict[str, Any]


class StrategyRunResultSchema(BaseModel):
    strategy_id: str
    status: Literal["ok", "warning", "fail"]
    message: str

    # ✅ explicitar warnings y disponibilidad de serie
    warnings: List[str] = Field(default_factory=list)
    series_available: bool = False
    series_error: Optional[str] = None

    n_windows: int
    oos_final_equity: float
    oos_total_return_pct: float
    oos_max_dd_worst_pct: float
    degradation_sharpe: Optional[float] = None

    diagnostics: Optional[Dict[str, Any]] = None

    windows: List[WindowRowSchema]


class CalibrationStrategiesInspectResponse(BaseModel):
    valid: bool
    status: Literal["ok", "warning", "fail"]
    checks: Dict[str, Any]
    message: str
    results: List[StrategyRunResultSchema]

    config: Optional[Dict[str, Any]] = None


class CalibrationStrategiesValidateResponse(CalibrationStrategiesInspectResponse):
    series: Dict[str, Any]
