"""Pydantic schemas for request/response validation."""

from datetime import datetime, timezone
from decimal import Decimal
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field, ConfigDict, field_validator
from enum import Enum


class OrderSide(str, Enum):
    """Order side."""
    BUY = "buy"
    SELL = "sell"


class OrderType(str, Enum):
    """Order type."""
    MARKET = "market"
    LIMIT = "limit"
    STOP_LOSS = "stop_loss"
    TAKE_PROFIT = "take_profit"
    TRAILING_STOP = "trailing_stop"
    OCO = "oco"
    ICEBERG = "iceberg"


class OrderStatus(str, Enum):
    """Order status."""
    PENDING = "pending"
    OPEN = "open"
    PARTIALLY_FILLED = "partially_filled"
    FILLED = "filled"
    CANCELLED = "cancelled"
    REJECTED = "rejected"
    EXPIRED = "expired"


# Trading Schemas
class OrderCreate(BaseModel):
    """Create order request."""
    exchange_id: int
    symbol: str
    side: OrderSide
    order_type: OrderType
    quantity: Decimal
    price: Optional[Decimal] = None
    strategy_id: Optional[int] = None
    paper_trading: bool = True


class OrderResponse(BaseModel):
    """Order response."""
    model_config = ConfigDict(from_attributes=True, populate_by_name=True)
    
    id: int
    exchange_id: int
    strategy_id: Optional[int]
    symbol: str
    order_type: OrderType
    side: OrderSide
    status: OrderStatus
    quantity: Decimal
    price: Optional[Decimal]
    filled_quantity: Decimal
    average_fill_price: Optional[Decimal]
    fee: Decimal
    paper_trading: bool
    created_at: datetime
    updated_at: datetime
    filled_at: Optional[datetime]

    @field_validator('created_at', 'updated_at', 'filled_at', mode='after')
    @classmethod
    def ensure_utc(cls, v: Optional[datetime]) -> Optional[datetime]:
        if v and v.tzinfo is None:
            return v.replace(tzinfo=timezone.utc)
        return v


class PositionResponse(BaseModel):
    """Position response."""
    model_config = ConfigDict(from_attributes=True, populate_by_name=True)
    
    symbol: str
    quantity: Decimal
    entry_price: Decimal
    current_price: Decimal
    unrealized_pnl: Decimal
    realized_pnl: Decimal


# Portfolio Schemas
class PortfolioResponse(BaseModel):
    """Portfolio response."""
    positions: List[Dict[str, Any]]
    performance: Dict[str, float]
    timestamp: str


class PortfolioHistoryResponse(BaseModel):
    """Portfolio history response."""
    dates: List[str]
    values: List[float]
    pnl: List[float]


# Strategy Schemas
class StrategyCreate(BaseModel):
    """Create strategy request."""
    name: str
    description: Optional[str] = None
    strategy_type: str
    class_name: str
    parameters: Dict[str, Any] = Field(default_factory=dict)
    timeframes: List[str] = Field(default_factory=lambda: ["1h"])
    paper_trading: bool = True
    schedule: Optional[Dict[str, Any]] = None


class StrategyUpdate(BaseModel):
    """Update strategy request."""
    name: Optional[str] = None
    description: Optional[str] = None
    parameters: Optional[Dict[str, Any]] = None
    timeframes: Optional[List[str]] = None
    enabled: Optional[bool] = None
    schedule: Optional[Dict[str, Any]] = None


class StrategyResponse(BaseModel):
    """Strategy response."""
    model_config = ConfigDict(from_attributes=True, populate_by_name=True)
    
    id: int
    name: str
    description: Optional[str]
    strategy_type: str
    class_name: str
    parameters: Dict[str, Any]
    timeframes: List[str]
    enabled: bool
    running: bool = False
    paper_trading: bool
    version: str
    schedule: Optional[Dict[str, Any]]
    created_at: datetime
    updated_at: datetime

    @field_validator('created_at', 'updated_at', mode='after')
    @classmethod
    def ensure_utc(cls, v: Optional[datetime]) -> Optional[datetime]:
        if v and v.tzinfo is None:
            return v.replace(tzinfo=timezone.utc)
        return v


# Backtesting Schemas
class BacktestRequest(BaseModel):
    """Backtest request."""
    strategy_id: int
    symbol: str
    exchange: str
    timeframe: str
    start_date: datetime
    end_date: datetime
    initial_capital: Decimal = Decimal("100.0")
    slippage: float = 0.001
    fee_rate: float = 0.001


class BacktestResponse(BaseModel):
    """Backtest response."""
    backtest_id: Optional[int] = None
    results: Dict[str, Any]
    status: str = "completed"


# Exchange Schemas
class ExchangeResponse(BaseModel):
    """Exchange response."""
    model_config = ConfigDict(from_attributes=True, populate_by_name=True)
    
    id: int
    name: str
    sandbox: bool
    read_only: bool
    enabled: bool
    created_at: datetime
    updated_at: datetime

    @field_validator('created_at', 'updated_at', mode='after')
    @classmethod
    def ensure_utc(cls, v: Optional[datetime]) -> Optional[datetime]:
        if v and v.tzinfo is None:
            return v.replace(tzinfo=timezone.utc)
        return v


# WebSocket Messages
class PriceUpdate(BaseModel):
    """Price update message."""
    exchange: str
    symbol: str
    price: Decimal
    timestamp: datetime


class OrderUpdate(BaseModel):
    """Order update message."""
    order_id: int
    status: OrderStatus
    filled_quantity: Optional[Decimal] = None
    timestamp: datetime
