"""
Market type definitions and configuration for backtesting.

Supports different market types with their specific trading conditions:
- SPOT: No leverage, no funding, long-only
- PERPETUAL: Leverage, funding rates, long/short
"""
from dataclasses import dataclass
from enum import Enum


class MarketType(Enum):
    """Supported market types for backtesting."""
    SPOT = "spot"
    PERPETUAL = "perpetual"


@dataclass(frozen=True)
class MarketConfig:
    """
    Configuration for a specific market type.
    
    Attributes:
        market_type: The market type enum value
        maker_fee: Maker fee as decimal (e.g., 0.0008 = 0.08%)
        taker_fee: Taker fee as decimal (e.g., 0.001 = 0.1%)
        max_leverage: Maximum allowed leverage
        funding_rate: Funding rate per 8 hours as decimal (perpetuals only)
        funding_interval_hours: Hours between funding payments
        maintenance_margin_rate: Rate for liquidation calculation
        supports_short: Whether short-selling is supported
    """
    market_type: MarketType
    maker_fee: float
    taker_fee: float
    max_leverage: int
    funding_rate: float
    funding_interval_hours: int
    maintenance_margin_rate: float
    supports_short: bool


# OKX-based default configurations
SPOT_CONFIG = MarketConfig(
    market_type=MarketType.SPOT,
    maker_fee=0.0008,       # 0.08%
    taker_fee=0.0010,       # 0.10%
    max_leverage=1,
    funding_rate=0.0,
    funding_interval_hours=0,
    maintenance_margin_rate=0.0,
    supports_short=False,
)

PERPETUAL_CONFIG = MarketConfig(
    market_type=MarketType.PERPETUAL,
    maker_fee=0.0002,       # 0.02%
    taker_fee=0.0005,       # 0.05%
    max_leverage=125,
    funding_rate=0.0001,    # 0.01% per 8 hours (simplified average)
    funding_interval_hours=8,
    maintenance_margin_rate=0.004,  # 0.4% for BTC on OKX
    supports_short=True,
)


def get_market_config(market_type: MarketType) -> MarketConfig:
    """
    Get the configuration for a specific market type.
    
    Args:
        market_type: The market type to get configuration for
        
    Returns:
        MarketConfig with default values for that market type
    """
    configs = {
        MarketType.SPOT: SPOT_CONFIG,
        MarketType.PERPETUAL: PERPETUAL_CONFIG,
    }
    return configs[market_type]


def get_ccxt_symbol(symbol: str, market_type: MarketType) -> str:
    """
    Convert a standard symbol to CCXT format for the given market type.
    
    Args:
        symbol: Standard symbol (e.g., 'BTC/USDT')
        market_type: The market type
        
    Returns:
        CCXT-formatted symbol (e.g., 'BTC/USDT:USDT' for perpetuals)
    """
    if market_type == MarketType.PERPETUAL:
        # OKX perpetual format: BTC/USDT:USDT
        if '/' in symbol:
            base, quote = symbol.split('/')
            return f"{symbol}:{quote}"
        elif '-' in symbol:
            base, quote = symbol.split('-')
            return f"{base}/{quote}:{quote}"
        else:
            # Assume base is symbol, quote is USDT default
            return f"{symbol}/USDT:USDT"
            
    # For spot, normalize dash to slash for CCXT
    if '-' in symbol:
        return symbol.replace('-', '/')
        
    return symbol


def calculate_leverage_stop_loss(
    leverage: int,
    maintenance_margin_rate: float = 0.004
) -> float:
    """
    Calculate the implicit stop-loss percentage from leverage.
    
    At a given leverage, liquidation occurs when the position loses
    approximately (1/leverage - maintenance_margin_rate) of its value.
    
    Args:
        leverage: Position leverage multiplier
        maintenance_margin_rate: Maintenance margin rate (default OKX BTC: 0.4%)
        
    Returns:
        Stop-loss percentage as decimal (e.g., 0.196 for 19.6%)
    """
    if leverage <= 1:
        return 1.0  # No forced stop for spot
    
    return (1 / leverage) - maintenance_margin_rate


def calculate_liquidation_price(
    entry_price: float,
    leverage: float,
    is_long: bool,
    maintenance_margin_rate: float = 0.004
) -> float:
    """
    Calculate the liquidation price for a leveraged position.
    
    Args:
        entry_price: Position entry price
        leverage: Position leverage
        is_long: True for long positions, False for short
        maintenance_margin_rate: Maintenance margin rate (default OKX BTC: 0.4%)
        
    Returns:
        Liquidation price
    """
    if leverage <= 1:
        return 0.0 if is_long else float('inf')
    
    # Simplified liquidation formula
    # Long: liq_price = entry * (1 - 1/leverage + maintenance_margin_rate)
    # Short: liq_price = entry * (1 + 1/leverage - maintenance_margin_rate)
    margin_ratio = 1 / leverage
    
    if is_long:
        liq_price = entry_price * (1 - margin_ratio + maintenance_margin_rate)
    else:
        liq_price = entry_price * (1 + margin_ratio - maintenance_margin_rate)
    
    return liq_price
