/**
 * Synor DEX SDK Types
 * 
 * Comprehensive types for decentralized exchange operations including
 * AMM swaps, liquidity pools, perpetual futures, and order books.
 */

// ==================== Configuration ====================

export interface DexConfig {
  apiKey: string;
  endpoint?: string;
  wsEndpoint?: string;
  timeout?: number;
  retries?: number;
  debug?: boolean;
}

// ==================== Token Types ====================

export interface Token {
  address: string;
  symbol: string;
  name: string;
  decimals: number;
  logoUri?: string;
  verified?: boolean;
}

export interface TokenAmount {
  token: Token;
  amount: bigint;
  formatted: string;
}

// ==================== Pool Types ====================

export interface Pool {
  id: string;
  tokenA: Token;
  tokenB: Token;
  reserveA: bigint;
  reserveB: bigint;
  fee: number;              // e.g., 0.003 = 0.3%
  tvl: bigint;
  volume24h: bigint;
  volume7d: bigint;
  apr: number;
  lpTokenAddress: string;
  lpTokenSupply: bigint;
  createdAt: number;
}

export interface PoolFilter {
  tokens?: string[];
  minTvl?: bigint;
  minVolume24h?: bigint;
  verified?: boolean;
  limit?: number;
  offset?: number;
}

export type PoolType = 'constant_product' | 'stable' | 'concentrated';

// ==================== Swap Types ====================

export interface QuoteParams {
  tokenIn: string;
  tokenOut: string;
  amountIn: bigint;
  slippage?: number;        // Default: 0.005 (0.5%)
}

export interface Quote {
  tokenIn: Token;
  tokenOut: Token;
  amountIn: bigint;
  amountOut: bigint;
  minAmountOut: bigint;
  priceImpact: number;
  fee: bigint;
  route: string[];
  executionPrice: number;
  pools: string[];
}

export interface SwapParams {
  tokenIn: string;
  tokenOut: string;
  amountIn: bigint;
  minAmountOut: bigint;
  deadline?: number;
  recipient?: string;
}

export interface SwapResult {
  transactionHash: string;
  amountIn: bigint;
  amountOut: bigint;
  executionPrice: number;
  priceImpact: number;
  fee: bigint;
  gasUsed: bigint;
  route: string[];
}

// ==================== Liquidity Types ====================

export interface AddLiquidityParams {
  tokenA: string;
  tokenB: string;
  amountA: bigint;
  amountB: bigint;
  minAmountA?: bigint;
  minAmountB?: bigint;
  deadline?: number;
}

export interface RemoveLiquidityParams {
  pool: string;
  lpAmount: bigint;
  minAmountA?: bigint;
  minAmountB?: bigint;
  deadline?: number;
}

export interface LiquidityResult {
  transactionHash: string;
  pool: string;
  amountA: bigint;
  amountB: bigint;
  lpTokens: bigint;
  share: number;
}

export interface LPPosition {
  pool: Pool;
  lpTokens: bigint;
  share: number;
  valueUsd: number;
  tokenAAmount: bigint;
  tokenBAmount: bigint;
  fees24h: bigint;
  feesTotal: bigint;
  impermanentLoss: number;
}

// ==================== Perpetual Futures Types ====================

export type PositionSide = 'long' | 'short';
export type OrderType = 'market' | 'limit' | 'stop_loss' | 'take_profit';
export type MarginType = 'cross' | 'isolated';

export interface PerpMarket {
  symbol: string;              // e.g., "BTC-PERP"
  baseToken: Token;
  quoteToken: Token;           // Usually USDC
  indexPrice: number;
  markPrice: number;
  fundingRate: number;         // Current funding rate (8h)
  nextFundingTime: number;
  openInterest: bigint;
  volume24h: bigint;
  maxLeverage: number;         // e.g., 100 for 100x
  maintenanceMargin: number;   // e.g., 0.005 = 0.5%
  initialMargin: number;       // e.g., 0.01 = 1%
  tickSize: number;
  minOrderSize: bigint;
  maxOrderSize: bigint;
}

export interface OpenPositionParams {
  market: string;
  side: PositionSide;
  size: bigint;                // Position size in base token
  leverage: number;            // 1-100x
  orderType: OrderType;
  limitPrice?: number;         // For limit orders
  stopLoss?: number;
  takeProfit?: number;
  marginType?: MarginType;
  reduceOnly?: boolean;
}

export interface ClosePositionParams {
  market: string;
  size?: bigint;               // Partial close if specified
  orderType: OrderType;
  limitPrice?: number;
}

export interface PerpPosition {
  id: string;
  market: string;
  side: PositionSide;
  size: bigint;
  entryPrice: number;
  markPrice: number;
  liquidationPrice: number;
  margin: bigint;
  leverage: number;
  marginType: MarginType;
  unrealizedPnl: bigint;
  realizedPnl: bigint;
  fundingPayment: bigint;
  createdAt: number;
  updatedAt: number;
}

export interface PerpOrder {
  id: string;
  market: string;
  side: PositionSide;
  size: bigint;
  price: number;
  orderType: OrderType;
  filled: bigint;
  remaining: bigint;
  status: 'open' | 'filled' | 'cancelled' | 'expired';
  reduceOnly: boolean;
  createdAt: number;
}

export interface ModifyPositionParams {
  positionId: string;
  newLeverage?: number;
  newMargin?: bigint;          // Add or remove margin
  newStopLoss?: number;
  newTakeProfit?: number;
}

export interface FundingPayment {
  market: string;
  amount: bigint;
  rate: number;
  timestamp: number;
}

// ==================== Order Book Types ====================

export interface OrderBookLevel {
  price: number;
  size: bigint;
  total: bigint;
}

export interface OrderBook {
  market: string;
  bids: OrderBookLevel[];
  asks: OrderBookLevel[];
  spread: number;
  timestamp: number;
}

export interface LimitOrderParams {
  market: string;
  side: 'buy' | 'sell';
  price: number;
  size: bigint;
  timeInForce?: 'GTC' | 'IOC' | 'FOK';
  postOnly?: boolean;
}

export interface Order {
  id: string;
  market: string;
  side: 'buy' | 'sell';
  price: number;
  size: bigint;
  filled: bigint;
  status: 'open' | 'filled' | 'partial' | 'cancelled';
  createdAt: number;
}

// ==================== Farming & Staking ====================

export interface Farm {
  id: string;
  pool: Pool;
  rewardToken: Token;
  rewardPerSecond: bigint;
  totalStaked: bigint;
  apr: number;
  startTime: number;
  endTime?: number;
}

export interface StakeParams {
  farm: string;
  amount: bigint;
}

export interface FarmPosition {
  farm: Farm;
  staked: bigint;
  pendingRewards: bigint;
  share: number;
}

// ==================== Analytics ====================

export interface OHLCV {
  timestamp: number;
  open: number;
  high: number;
  low: number;
  close: number;
  volume: bigint;
}

export interface TradeHistory {
  id: string;
  market: string;
  side: 'buy' | 'sell';
  price: number;
  size: bigint;
  timestamp: number;
  maker: string;
  taker: string;
}

export interface VolumeStats {
  volume24h: bigint;
  volume7d: bigint;
  volume30d: bigint;
  trades24h: number;
  uniqueTraders24h: number;
}

export interface TVLStats {
  total: bigint;
  byPool: Record<string, bigint>;
  history: { timestamp: number; tvl: bigint }[];
}

// ==================== Events & Subscriptions ====================

export interface Subscription {
  id: string;
  channel: string;
  cancel: () => void;
}

export type PriceCallback = (price: { market: string; price: number; timestamp: number }) => void;
export type TradeCallback = (trade: TradeHistory) => void;
export type OrderBookCallback = (orderBook: OrderBook) => void;
export type PositionCallback = (position: PerpPosition) => void;

// ==================== Errors ====================

export class DexError extends Error {
  code?: string;
  statusCode?: number;
  constructor(message: string, code?: string, statusCode?: number) {
    super(message);
    this.name = 'DexError';
    this.code = code;
    this.statusCode = statusCode;
  }
}

export class InsufficientLiquidityError extends DexError {
  constructor(message = 'Insufficient liquidity for this trade') {
    super(message, 'INSUFFICIENT_LIQUIDITY');
  }
}

export class SlippageExceededError extends DexError {
  constructor(message = 'Slippage tolerance exceeded') {
    super(message, 'SLIPPAGE_EXCEEDED');
  }
}

export class InsufficientMarginError extends DexError {
  constructor(message = 'Insufficient margin for position') {
    super(message, 'INSUFFICIENT_MARGIN');
  }
}

export class LiquidationError extends DexError {
  constructor(message = 'Position would be liquidated') {
    super(message, 'LIQUIDATION_RISK');
  }
}
