"""SQLAlchemy database models for persistent storage."""

from datetime import datetime
from decimal import Decimal
from typing import Optional

from sqlalchemy import (
    Column,
    String,
    DateTime,
    Numeric,
    Integer,
    Text,
    JSON,
    ForeignKey,
    Index,
    UniqueConstraint,
)
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func

Base = declarative_base()


class MarketDataModel(Base):
    """Market data table for OHLCV storage."""
    
    __tablename__ = "market_data"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    symbol = Column(String(20), nullable=False, index=True)
    timestamp = Column(DateTime, nullable=False, index=True)
    open = Column(Numeric(20, 8), nullable=False)
    high = Column(Numeric(20, 8), nullable=False)
    low = Column(Numeric(20, 8), nullable=False)
    close = Column(Numeric(20, 8), nullable=False)
    volume = Column(Numeric(20, 8), nullable=False)
    exchange = Column(String(50), nullable=False, index=True)
    created_at = Column(DateTime, default=func.now())
    
    __table_args__ = (
        UniqueConstraint("symbol", "timestamp", "exchange", name="uq_market_data"),
        Index("idx_market_data_symbol_timestamp", "symbol", "timestamp"),
        Index("idx_market_data_exchange_timestamp", "exchange", "timestamp"),
    )
    
    def __repr__(self):
        return f"<MarketData(symbol={self.symbol}, timestamp={self.timestamp}, close={self.close})>"


class TradingSignalModel(Base):
    """Trading signals generated by strategies."""
    
    __tablename__ = "trading_signals"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    symbol = Column(String(20), nullable=False, index=True)
    action = Column(String(10), nullable=False)  # BUY, SELL, HOLD
    confidence = Column(Numeric(5, 4), nullable=False)  # 0.0000 to 1.0000
    timestamp = Column(DateTime, nullable=False, index=True)
    strategy_name = Column(String(100), nullable=False, index=True)
    price = Column(Numeric(20, 8), nullable=True)
    signal_metadata = Column(JSON, nullable=True)
    created_at = Column(DateTime, default=func.now())
    
    __table_args__ = (
        Index("idx_symbol_strategy_timestamp", "symbol", "strategy_name", "timestamp"),
        Index("idx_strategy_timestamp", "strategy_name", "timestamp"),
    )
    
    def __repr__(self):
        return f"<TradingSignal(symbol={self.symbol}, action={self.action}, strategy={self.strategy_name})>"


class OrderModel(Base):
    """Order execution records."""
    
    __tablename__ = "orders"
    
    id = Column(String(100), primary_key=True)  # Exchange order ID
    symbol = Column(String(20), nullable=False, index=True)
    side = Column(String(10), nullable=False)  # BUY, SELL
    amount = Column(Numeric(20, 8), nullable=False)
    price = Column(Numeric(20, 8), nullable=True)
    order_type = Column(String(20), nullable=False)  # MARKET, LIMIT, etc.
    status = Column(String(20), nullable=False, index=True)
    timestamp = Column(DateTime, nullable=False, index=True)
    exchange = Column(String(50), nullable=False, index=True)
    filled_amount = Column(Numeric(20, 8), nullable=False, default=0)
    average_fill_price = Column(Numeric(20, 8), nullable=True)
    fees = Column(Numeric(20, 8), nullable=False, default=0)
    client_order_id = Column(String(100), nullable=True, index=True)
    created_at = Column(DateTime, default=func.now())
    updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
    
    # Relationship to trades
    trades = relationship("TradeModel", back_populates="order")
    
    __table_args__ = (
        Index("idx_orders_symbol_status", "symbol", "status"),
        Index("idx_orders_exchange_timestamp", "exchange", "timestamp"),
        Index("idx_orders_client_order_id", "client_order_id"),
    )
    
    def __repr__(self):
        return f"<Order(id={self.id}, symbol={self.symbol}, side={self.side}, status={self.status})>"


class PositionModel(Base):
    """Current and historical positions."""
    
    __tablename__ = "positions"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    symbol = Column(String(20), nullable=False, index=True)
    size = Column(Numeric(20, 8), nullable=False)
    entry_price = Column(Numeric(20, 8), nullable=False)
    current_price = Column(Numeric(20, 8), nullable=False)
    side = Column(String(10), nullable=False)  # BUY, SELL
    exchange = Column(String(50), nullable=False, index=True)
    opened_at = Column(DateTime, nullable=False)
    updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
    closed_at = Column(DateTime, nullable=True)
    is_active = Column(String(10), nullable=False, default="true", index=True)
    
    __table_args__ = (
        Index("idx_symbol_active", "symbol", "is_active"),
        Index("idx_exchange_active", "exchange", "is_active"),
    )
    
    def __repr__(self):
        return f"<Position(symbol={self.symbol}, size={self.size}, entry_price={self.entry_price})>"


class TradeModel(Base):
    """Completed trade records."""
    
    __tablename__ = "trades"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    order_id = Column(String(100), ForeignKey("orders.id"), nullable=False, index=True)
    symbol = Column(String(20), nullable=False, index=True)
    side = Column(String(10), nullable=False)  # BUY, SELL
    amount = Column(Numeric(20, 8), nullable=False)
    price = Column(Numeric(20, 8), nullable=False)
    fees = Column(Numeric(20, 8), nullable=False, default=0)
    timestamp = Column(DateTime, nullable=False, index=True)
    exchange = Column(String(50), nullable=False, index=True)
    trade_id = Column(String(100), nullable=True)  # Exchange trade ID
    created_at = Column(DateTime, default=func.now())
    
    # Relationship to order
    order = relationship("OrderModel", back_populates="trades")
    
    __table_args__ = (
        Index("idx_trades_symbol_timestamp", "symbol", "timestamp"),
        Index("idx_trades_exchange_timestamp", "exchange", "timestamp"),
    )
    
    def __repr__(self):
        return f"<Trade(symbol={self.symbol}, side={self.side}, amount={self.amount}, price={self.price})>"


class StrategyPerformanceModel(Base):
    """Strategy performance metrics tracking."""
    
    __tablename__ = "strategy_performance"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    strategy_name = Column(String(100), nullable=False, index=True)
    symbol = Column(String(20), nullable=False, index=True)
    period_start = Column(DateTime, nullable=False)
    period_end = Column(DateTime, nullable=False)
    total_trades = Column(Integer, nullable=False, default=0)
    winning_trades = Column(Integer, nullable=False, default=0)
    losing_trades = Column(Integer, nullable=False, default=0)
    total_pnl = Column(Numeric(20, 8), nullable=False, default=0)
    max_drawdown = Column(Numeric(20, 8), nullable=False, default=0)
    sharpe_ratio = Column(Numeric(10, 4), nullable=True)
    win_rate = Column(Numeric(5, 4), nullable=False, default=0)  # 0.0000 to 1.0000
    avg_win = Column(Numeric(20, 8), nullable=False, default=0)
    avg_loss = Column(Numeric(20, 8), nullable=False, default=0)
    created_at = Column(DateTime, default=func.now())
    
    __table_args__ = (
        Index("idx_strategy_symbol", "strategy_name", "symbol"),
        Index("idx_strategy_period", "strategy_name", "period_start", "period_end"),
    )
    
    def __repr__(self):
        return f"<StrategyPerformance(strategy={self.strategy_name}, symbol={self.symbol}, pnl={self.total_pnl})>"


class RiskEventModel(Base):
    """Risk management event logging."""
    
    __tablename__ = "risk_events"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    event_type = Column(String(50), nullable=False, index=True)  # STOP_LOSS, POSITION_LIMIT, etc.
    symbol = Column(String(20), nullable=False, index=True)
    description = Column(Text, nullable=False)
    severity = Column(String(20), nullable=False, index=True)  # LOW, MEDIUM, HIGH, CRITICAL
    triggered_value = Column(Numeric(20, 8), nullable=True)
    threshold_value = Column(Numeric(20, 8), nullable=True)
    action_taken = Column(String(100), nullable=True)
    timestamp = Column(DateTime, nullable=False, index=True)
    risk_metadata = Column(JSON, nullable=True)
    created_at = Column(DateTime, default=func.now())
    
    __table_args__ = (
        Index("idx_event_type_timestamp", "event_type", "timestamp"),
        Index("idx_symbol_severity", "symbol", "severity"),
        Index("idx_severity_timestamp", "severity", "timestamp"),
    )
    
    def __repr__(self):
        return f"<RiskEvent(type={self.event_type}, symbol={self.symbol}, severity={self.severity})>"


class UnifiedMarketDataModel(Base):
    """Unified market data table for multi-market support."""
    
    __tablename__ = "unified_market_data"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    base_asset = Column(String(20), nullable=False, index=True)
    quote_asset = Column(String(20), nullable=False, index=True)
    native_symbol = Column(String(50), nullable=False, index=True)
    market_type = Column(String(20), nullable=False, index=True)  # CRYPTO, FOREX
    timestamp = Column(DateTime, nullable=False, index=True)
    open = Column(Numeric(20, 8), nullable=False)
    high = Column(Numeric(20, 8), nullable=False)
    low = Column(Numeric(20, 8), nullable=False)
    close = Column(Numeric(20, 8), nullable=False)
    volume = Column(Numeric(20, 8), nullable=False)
    source = Column(String(50), nullable=False, index=True)  # Exchange or broker name
    session_name = Column(String(50), nullable=True, index=True)
    session_active = Column(String(10), nullable=True)  # true/false as string
    created_at = Column(DateTime, default=func.now())
    
    __table_args__ = (
        UniqueConstraint(
            "base_asset", "quote_asset", "market_type", "timestamp", "source",
            name="uq_unified_market_data"
        ),
        Index("idx_unified_symbol_timestamp", "base_asset", "quote_asset", "market_type", "timestamp"),
        Index("idx_unified_market_type_timestamp", "market_type", "timestamp"),
        Index("idx_unified_source_timestamp", "source", "timestamp"),
        Index("idx_unified_session_timestamp", "session_name", "timestamp"),
    )
    
    def __repr__(self):
        return f"<UnifiedMarketData(symbol={self.base_asset}/{self.quote_asset}, market={self.market_type}, timestamp={self.timestamp})>"


class MarketSessionModel(Base):
    """Market session information and schedules."""
    
    __tablename__ = "market_sessions"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    market_type = Column(String(20), nullable=False, index=True)  # CRYPTO, FOREX
    session_name = Column(String(50), nullable=False, index=True)
    is_active = Column(String(10), nullable=False)  # true/false as string
    next_open = Column(DateTime, nullable=True)
    next_close = Column(DateTime, nullable=True)
    timezone = Column(String(50), nullable=True)
    created_at = Column(DateTime, default=func.now())
    updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
    
    __table_args__ = (
        UniqueConstraint("market_type", "session_name", name="uq_market_session"),
        Index("idx_market_session_type", "market_type"),
        Index("idx_market_session_active", "is_active"),
    )
    
    def __repr__(self):
        return f"<MarketSession(market={self.market_type}, session={self.session_name}, active={self.is_active})>"


class CrossMarketCorrelationModel(Base):
    """Cross-market correlation data storage."""
    
    __tablename__ = "cross_market_correlations"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    symbol1_base = Column(String(20), nullable=False, index=True)
    symbol1_quote = Column(String(20), nullable=False, index=True)
    symbol1_market_type = Column(String(20), nullable=False, index=True)
    symbol2_base = Column(String(20), nullable=False, index=True)
    symbol2_quote = Column(String(20), nullable=False, index=True)
    symbol2_market_type = Column(String(20), nullable=False, index=True)
    correlation = Column(Numeric(10, 8), nullable=False)  # -1.0000 to 1.0000
    period_days = Column(Integer, nullable=False)
    calculated_at = Column(DateTime, nullable=False, index=True)
    created_at = Column(DateTime, default=func.now())
    
    __table_args__ = (
        Index("idx_correlation_symbols", "symbol1_base", "symbol1_quote", "symbol2_base", "symbol2_quote"),
        Index("idx_correlation_markets", "symbol1_market_type", "symbol2_market_type"),
        Index("idx_correlation_period", "period_days", "calculated_at"),
    )
    
    def __repr__(self):
        return f"<CrossMarketCorrelation({self.symbol1_base}/{self.symbol1_quote} vs {self.symbol2_base}/{self.symbol2_quote}, corr={self.correlation})>"


class MarketHolidayModel(Base):
    """Market-specific holiday calendar."""
    
    __tablename__ = "market_holidays"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    market_type = Column(String(20), nullable=False, index=True)
    holiday_date = Column(DateTime, nullable=False, index=True)
    holiday_name = Column(String(100), nullable=False)
    description = Column(Text, nullable=True)
    affects_trading = Column(String(10), nullable=False, default="true")  # true/false
    created_at = Column(DateTime, default=func.now())
    
    __table_args__ = (
        UniqueConstraint("market_type", "holiday_date", name="uq_market_holiday"),
        Index("idx_holiday_market_date", "market_type", "holiday_date"),
    )
    
    def __repr__(self):
        return f"<MarketHoliday(market={self.market_type}, date={self.holiday_date}, name={self.holiday_name})>"