"""
Synor DEX SDK Types
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, List, Callable, Any
from decimal import Decimal


class PoolType(Enum):
    """Type of liquidity pool"""
    CONSTANT_PRODUCT = "constant_product"  # x * y = k
    STABLE = "stable"  # Optimized for stablecoins
    CONCENTRATED = "concentrated"  # Uniswap v3 style


class PositionSide(Enum):
    """Perpetual position side"""
    LONG = "long"
    SHORT = "short"


class OrderType(Enum):
    """Order type for perpetuals"""
    MARKET = "market"
    LIMIT = "limit"
    STOP_MARKET = "stop_market"
    STOP_LIMIT = "stop_limit"
    TAKE_PROFIT = "take_profit"
    TAKE_PROFIT_LIMIT = "take_profit_limit"


class MarginType(Enum):
    """Margin type for perpetuals"""
    CROSS = "cross"
    ISOLATED = "isolated"


class TimeInForce(Enum):
    """Time in force for limit orders"""
    GTC = "GTC"  # Good Till Cancel
    IOC = "IOC"  # Immediate Or Cancel
    FOK = "FOK"  # Fill Or Kill
    GTD = "GTD"  # Good Till Date


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


class DexError(Exception):
    """DEX SDK error"""
    def __init__(self, message: str, code: Optional[str] = None, status: Optional[int] = None):
        super().__init__(message)
        self.message = message
        self.code = code
        self.status = status


@dataclass
class DexConfig:
    """DEX client configuration"""
    api_key: str
    endpoint: str = "https://dex.synor.io/v1"
    ws_endpoint: str = "wss://dex.synor.io/v1/ws"
    timeout: int = 30000
    retries: int = 3
    debug: bool = False


@dataclass
class Token:
    """Token information"""
    address: str
    symbol: str
    name: str
    decimals: int
    total_supply: int
    price_usd: Optional[float] = None
    logo_url: Optional[str] = None
    verified: bool = False


@dataclass
class Pool:
    """Liquidity pool information"""
    id: str
    token_a: Token
    token_b: Token
    pool_type: PoolType
    reserve_a: int
    reserve_b: int
    fee: float
    tvl_usd: float
    volume_24h: float
    apr: float
    lp_token_address: str
    tick_spacing: Optional[int] = None  # For concentrated liquidity
    sqrt_price: Optional[str] = None


@dataclass
class PoolFilter:
    """Pool list filter"""
    tokens: Optional[List[str]] = None
    min_tvl: Optional[float] = None
    min_volume_24h: Optional[float] = None
    verified: Optional[bool] = None
    limit: Optional[int] = None
    offset: Optional[int] = None


@dataclass
class Quote:
    """Swap quote"""
    token_in: str
    token_out: str
    amount_in: int
    amount_out: int
    price_impact: float
    route: List[str]
    fee: int
    minimum_received: int
    expires_at: int


@dataclass
class QuoteParams:
    """Parameters for getting a quote"""
    token_in: str
    token_out: str
    amount_in: int
    slippage: float = 0.005


@dataclass
class SwapParams:
    """Parameters for executing a swap"""
    token_in: str
    token_out: str
    amount_in: int
    min_amount_out: int
    deadline: Optional[int] = None
    recipient: Optional[str] = None


@dataclass
class SwapResult:
    """Swap execution result"""
    transaction_hash: str
    amount_in: int
    amount_out: int
    effective_price: float
    fee_paid: int
    route: List[str]


@dataclass
class AddLiquidityParams:
    """Parameters for adding liquidity"""
    token_a: str
    token_b: str
    amount_a: int
    amount_b: int
    min_amount_a: Optional[int] = None
    min_amount_b: Optional[int] = None
    deadline: Optional[int] = None
    tick_lower: Optional[int] = None  # For concentrated liquidity
    tick_upper: Optional[int] = None


@dataclass
class RemoveLiquidityParams:
    """Parameters for removing liquidity"""
    pool: str
    lp_amount: int
    min_amount_a: Optional[int] = None
    min_amount_b: Optional[int] = None
    deadline: Optional[int] = None


@dataclass
class LiquidityResult:
    """Liquidity operation result"""
    transaction_hash: str
    amount_a: int
    amount_b: int
    lp_tokens: int
    pool_share: float


@dataclass
class LPPosition:
    """LP position"""
    pool_id: str
    lp_tokens: int
    token_a_amount: int
    token_b_amount: int
    value_usd: float
    unclaimed_fees_a: int
    unclaimed_fees_b: int
    impermanent_loss: float
    tick_lower: Optional[int] = None
    tick_upper: Optional[int] = None
    in_range: Optional[bool] = None


@dataclass
class PerpMarket:
    """Perpetual futures market"""
    symbol: str
    base_asset: str
    quote_asset: str
    index_price: float
    mark_price: float
    funding_rate: float
    next_funding_time: int
    open_interest: int
    volume_24h: float
    price_change_24h: float
    max_leverage: int
    min_order_size: int
    tick_size: float
    maintenance_margin: float
    initial_margin: float


@dataclass
class OpenPositionParams:
    """Parameters for opening a perpetual position"""
    market: str
    side: PositionSide
    size: int
    leverage: int  # 1-100x
    order_type: OrderType
    limit_price: Optional[float] = None
    stop_loss: Optional[float] = None
    take_profit: Optional[float] = None
    margin_type: MarginType = MarginType.CROSS
    reduce_only: bool = False


@dataclass
class ClosePositionParams:
    """Parameters for closing a perpetual position"""
    market: str
    size: Optional[int] = None  # None = close entire position
    order_type: OrderType = OrderType.MARKET
    limit_price: Optional[float] = None


@dataclass
class ModifyPositionParams:
    """Parameters for modifying a perpetual position"""
    position_id: str
    new_leverage: Optional[int] = None
    new_margin: Optional[int] = None
    new_stop_loss: Optional[float] = None
    new_take_profit: Optional[float] = None


@dataclass
class PerpPosition:
    """Perpetual position"""
    id: str
    market: str
    side: PositionSide
    size: int
    entry_price: float
    mark_price: float
    liquidation_price: float
    margin: int
    leverage: int
    unrealized_pnl: int
    realized_pnl: int
    margin_ratio: float
    stop_loss: Optional[float] = None
    take_profit: Optional[float] = None
    created_at: int = 0
    updated_at: int = 0


@dataclass
class PerpOrder:
    """Perpetual order"""
    id: str
    market: str
    side: PositionSide
    order_type: OrderType
    size: int
    price: Optional[float] = None
    filled_size: int = 0
    status: OrderStatus = OrderStatus.PENDING
    reduce_only: bool = False
    created_at: int = 0


@dataclass
class FundingPayment:
    """Funding payment record"""
    market: str
    amount: int
    rate: float
    position_size: int
    timestamp: int


@dataclass
class OrderBookEntry:
    """Order book entry"""
    price: float
    size: int
    orders: int


@dataclass
class OrderBook:
    """Order book"""
    market: str
    bids: List[OrderBookEntry]
    asks: List[OrderBookEntry]
    timestamp: int


@dataclass
class LimitOrderParams:
    """Parameters for limit orders"""
    market: str
    side: str  # 'buy' or 'sell'
    price: float
    size: int
    time_in_force: TimeInForce = TimeInForce.GTC
    post_only: bool = False


@dataclass
class Order:
    """Limit order"""
    id: str
    market: str
    side: str
    price: float
    size: int
    filled_size: int
    status: OrderStatus
    time_in_force: TimeInForce
    post_only: bool
    created_at: int
    updated_at: int


@dataclass
class Farm:
    """Yield farm"""
    id: str
    name: str
    stake_token: Token
    reward_tokens: List[Token]
    tvl_usd: float
    apr: float
    daily_rewards: List[int]
    lockup_period: Optional[int] = None
    min_stake: Optional[int] = None


@dataclass
class StakeParams:
    """Parameters for staking"""
    farm: str
    amount: int


@dataclass
class FarmPosition:
    """Farm position"""
    farm_id: str
    staked_amount: int
    pending_rewards: List[int]
    staked_at: int
    unlock_at: Optional[int] = None


@dataclass
class OHLCV:
    """OHLCV candle data"""
    timestamp: int
    open: float
    high: float
    low: float
    close: float
    volume: float


@dataclass
class TradeHistory:
    """Trade history entry"""
    id: str
    market: str
    side: str
    price: float
    size: int
    timestamp: int
    maker: str
    taker: str


@dataclass
class VolumeStats:
    """Volume statistics"""
    volume_24h: float
    volume_7d: float
    volume_30d: float
    trades_24h: int
    unique_traders_24h: int


@dataclass
class TVLStats:
    """TVL statistics"""
    total_tvl: float
    pools_tvl: float
    farms_tvl: float
    perps_tvl: float


@dataclass
class Subscription:
    """WebSocket subscription"""
    id: str
    channel: str
    cancel: Callable[[], None]


# Callback types
PriceCallback = Callable[[float], None]
TradeCallback = Callable[[TradeHistory], None]
OrderBookCallback = Callable[[OrderBook], None]
PositionCallback = Callable[[PerpPosition], None]
