/**
 * Synor DEX SDK Examples for JavaScript/TypeScript
 *
 * Demonstrates decentralized exchange operations:
 * - Spot trading (market/limit orders)
 * - Perpetual futures trading
 * - Liquidity provision
 * - Order management
 * - Real-time market data
 */

import {
  SynorDex,
  DexConfig,
  Network,
  OrderSide,
  OrderType,
  TimeInForce,
  PositionSide,
  MarginType,
} from '../src/dex';

async function main() {
  // Initialize client
  const config: DexConfig = {
    apiKey: process.env.SYNOR_API_KEY || 'your-api-key',
    endpoint: 'https://dex.synor.io/v1',
    wsEndpoint: 'wss://dex.synor.io/v1/ws',
    timeout: 30000,
    retries: 3,
    debug: false,
    defaultNetwork: Network.Mainnet,
  };

  const dex = new SynorDex(config);

  try {
    // Check service health
    const healthy = await dex.healthCheck();
    console.log(`Service healthy: ${healthy}\n`);

    // Example 1: Market data
    await marketDataExample(dex);

    // Example 2: Spot trading
    await spotTradingExample(dex);

    // Example 3: Perpetual futures
    await perpetualFuturesExample(dex);

    // Example 4: Liquidity provision
    await liquidityExample(dex);

    // Example 5: Order management
    await orderManagementExample(dex);

    // Example 6: Account information
    await accountExample(dex);

    // Example 7: Real-time streaming
    await streamingExample(dex);
  } finally {
    dex.close();
  }
}

/**
 * Market data and orderbook
 */
async function marketDataExample(dex: SynorDex): Promise<void> {
  console.log('=== Market Data ===');

  // Get all trading pairs
  const pairs = await dex.markets.getPairs();
  console.log(`Available trading pairs: ${pairs.length}`);
  for (const pair of pairs.slice(0, 5)) {
    console.log(`  ${pair.symbol}: ${pair.baseAsset}/${pair.quoteAsset}`);
  }

  // Get ticker for a specific pair
  const ticker = await dex.markets.getTicker('SYN-USDT');
  console.log(`\nSYN-USDT Ticker:`);
  console.log(`  Last price: $${ticker.lastPrice}`);
  console.log(`  24h change: ${ticker.priceChangePercent}%`);
  console.log(`  24h high: $${ticker.highPrice}`);
  console.log(`  24h low: $${ticker.lowPrice}`);
  console.log(`  24h volume: ${ticker.volume} SYN`);
  console.log(`  24h quote volume: $${ticker.quoteVolume}`);

  // Get orderbook
  const orderbook = await dex.markets.getOrderbook('SYN-USDT', 10);
  console.log(`\nOrderbook (top 5):`);
  console.log('  Bids:');
  for (const bid of orderbook.bids.slice(0, 5)) {
    console.log(`    $${bid.price} - ${bid.quantity} SYN`);
  }
  console.log('  Asks:');
  for (const ask of orderbook.asks.slice(0, 5)) {
    console.log(`    $${ask.price} - ${ask.quantity} SYN`);
  }

  // Get recent trades
  const trades = await dex.markets.getTrades('SYN-USDT', 5);
  console.log(`\nRecent trades:`);
  for (const trade of trades) {
    const side = trade.isBuyerMaker ? 'SELL' : 'BUY';
    console.log(`  ${side} ${trade.quantity} @ $${trade.price}`);
  }

  // Get OHLCV candles
  const candles = await dex.markets.getCandles('SYN-USDT', '1h', 5);
  console.log(`\nHourly candles:`);
  for (const candle of candles) {
    console.log(`  ${new Date(candle.openTime).toISOString()}: O=${candle.open} H=${candle.high} L=${candle.low} C=${candle.close}`);
  }

  console.log('');
}

/**
 * Spot trading operations
 */
async function spotTradingExample(dex: SynorDex): Promise<void> {
  console.log('=== Spot Trading ===');

  // Place a market buy order
  console.log('Placing market buy order...');
  const marketBuy = await dex.spot.createOrder({
    symbol: 'SYN-USDT',
    side: OrderSide.Buy,
    type: OrderType.Market,
    quantity: 10, // Buy 10 SYN
  });
  console.log(`Market buy order: ${marketBuy.orderId}`);
  console.log(`  Status: ${marketBuy.status}`);
  console.log(`  Filled: ${marketBuy.executedQty} SYN`);
  console.log(`  Avg price: $${marketBuy.avgPrice}`);

  // Place a limit sell order
  console.log('\nPlacing limit sell order...');
  const limitSell = await dex.spot.createOrder({
    symbol: 'SYN-USDT',
    side: OrderSide.Sell,
    type: OrderType.Limit,
    quantity: 5,
    price: 15.50, // Sell at $15.50
    timeInForce: TimeInForce.GTC, // Good till cancelled
  });
  console.log(`Limit sell order: ${limitSell.orderId}`);
  console.log(`  Price: $${limitSell.price}`);
  console.log(`  Status: ${limitSell.status}`);

  // Place a stop-loss order
  console.log('\nPlacing stop-loss order...');
  const stopLoss = await dex.spot.createOrder({
    symbol: 'SYN-USDT',
    side: OrderSide.Sell,
    type: OrderType.StopLoss,
    quantity: 10,
    stopPrice: 12.00, // Trigger at $12.00
  });
  console.log(`Stop-loss order: ${stopLoss.orderId}`);
  console.log(`  Stop price: $${stopLoss.stopPrice}`);

  // Place a take-profit limit order
  console.log('\nPlacing take-profit order...');
  const takeProfit = await dex.spot.createOrder({
    symbol: 'SYN-USDT',
    side: OrderSide.Sell,
    type: OrderType.TakeProfitLimit,
    quantity: 10,
    price: 20.00, // Sell at $20.00
    stopPrice: 19.50, // Trigger at $19.50
    timeInForce: TimeInForce.GTC,
  });
  console.log(`Take-profit order: ${takeProfit.orderId}`);

  console.log('');
}

/**
 * Perpetual futures trading
 */
async function perpetualFuturesExample(dex: SynorDex): Promise<void> {
  console.log('=== Perpetual Futures ===');

  // Get perpetual markets
  const markets = await dex.perpetuals.getMarkets();
  console.log(`Available perpetual markets: ${markets.length}`);
  for (const market of markets.slice(0, 3)) {
    console.log(`  ${market.symbol}: ${market.maxLeverage}x max leverage, ${market.maintenanceMarginRate}% MMR`);
  }

  // Get funding rate
  const funding = await dex.perpetuals.getFundingRate('SYN-USDT-PERP');
  console.log(`\nFunding rate for SYN-USDT-PERP:`);
  console.log(`  Current rate: ${(funding.fundingRate * 100).toFixed(4)}%`);
  console.log(`  Predicted rate: ${(funding.predictedRate * 100).toFixed(4)}%`);
  console.log(`  Next funding: ${new Date(funding.nextFundingTime).toISOString()}`);

  // Set leverage
  await dex.perpetuals.setLeverage('SYN-USDT-PERP', 10);
  console.log('\nLeverage set to 10x');

  // Set margin type (isolated/cross)
  await dex.perpetuals.setMarginType('SYN-USDT-PERP', MarginType.Isolated);
  console.log('Margin type set to Isolated');

  // Open a long position
  console.log('\nOpening long position...');
  const longOrder = await dex.perpetuals.createOrder({
    symbol: 'SYN-USDT-PERP',
    side: OrderSide.Buy,
    positionSide: PositionSide.Long,
    type: OrderType.Market,
    quantity: 100, // 100 contracts
  });
  console.log(`Long position opened: ${longOrder.orderId}`);
  console.log(`  Entry price: $${longOrder.avgPrice}`);
  console.log(`  Position size: ${longOrder.executedQty} contracts`);

  // Set stop-loss and take-profit
  console.log('\nSetting SL/TP...');
  await dex.perpetuals.createOrder({
    symbol: 'SYN-USDT-PERP',
    side: OrderSide.Sell,
    positionSide: PositionSide.Long,
    type: OrderType.StopMarket,
    quantity: 100,
    stopPrice: 12.00, // Stop-loss at $12
    reduceOnly: true,
  });
  console.log('  Stop-loss set at $12.00');

  await dex.perpetuals.createOrder({
    symbol: 'SYN-USDT-PERP',
    side: OrderSide.Sell,
    positionSide: PositionSide.Long,
    type: OrderType.TakeProfitMarket,
    quantity: 100,
    stopPrice: 18.00, // Take-profit at $18
    reduceOnly: true,
  });
  console.log('  Take-profit set at $18.00');

  // Get position info
  const positions = await dex.perpetuals.getPositions('SYN-USDT-PERP');
  for (const pos of positions) {
    console.log(`\nPosition info:`);
    console.log(`  Symbol: ${pos.symbol}`);
    console.log(`  Side: ${pos.positionSide}`);
    console.log(`  Size: ${pos.positionAmount} contracts`);
    console.log(`  Entry: $${pos.entryPrice}`);
    console.log(`  Mark: $${pos.markPrice}`);
    console.log(`  PnL: $${pos.unrealizedPnl} (${pos.unrealizedPnlPercent}%)`);
    console.log(`  Leverage: ${pos.leverage}x`);
    console.log(`  Liq. price: $${pos.liquidationPrice}`);
  }

  // Close position
  console.log('\nClosing position...');
  await dex.perpetuals.closePosition('SYN-USDT-PERP', PositionSide.Long);
  console.log('Position closed');

  console.log('');
}

/**
 * Liquidity provision
 */
async function liquidityExample(dex: SynorDex): Promise<void> {
  console.log('=== Liquidity Provision ===');

  // Get available pools
  const pools = await dex.liquidity.getPools();
  console.log(`Available liquidity pools: ${pools.length}`);
  for (const pool of pools.slice(0, 3)) {
    console.log(`  ${pool.name}:`);
    console.log(`    TVL: $${pool.tvl.toLocaleString()}`);
    console.log(`    APY: ${pool.apy.toFixed(2)}%`);
    console.log(`    Fee tier: ${pool.feeTier}%`);
  }

  // Get pool details
  const pool = await dex.liquidity.getPool('SYN-USDT');
  console.log(`\nSYN-USDT Pool details:`);
  console.log(`  Reserve A: ${pool.reserveA} SYN`);
  console.log(`  Reserve B: ${pool.reserveB} USDT`);
  console.log(`  Total shares: ${pool.totalShares}`);
  console.log(`  Your shares: ${pool.userShares}`);

  // Add liquidity
  console.log('\nAdding liquidity...');
  const addResult = await dex.liquidity.addLiquidity({
    poolId: 'SYN-USDT',
    amountA: 100, // 100 SYN
    amountB: 1400, // 1400 USDT
    slippageTolerance: 0.5, // 0.5% slippage
  });
  console.log(`Liquidity added:`);
  console.log(`  Shares received: ${addResult.sharesReceived}`);
  console.log(`  Amount A deposited: ${addResult.amountADeposited}`);
  console.log(`  Amount B deposited: ${addResult.amountBDeposited}`);

  // Get LP positions
  const lpPositions = await dex.liquidity.getPositions();
  console.log(`\nYour LP positions:`);
  for (const lp of lpPositions) {
    console.log(`  ${lp.poolId}: ${lp.shares} shares ($${lp.valueUsd})`);
    console.log(`    Fees earned: $${lp.feesEarned}`);
  }

  // Remove liquidity
  console.log('\nRemoving liquidity...');
  const removeResult = await dex.liquidity.removeLiquidity({
    poolId: 'SYN-USDT',
    shares: addResult.sharesReceived * 0.5, // Remove 50%
    slippageTolerance: 0.5,
  });
  console.log(`Liquidity removed:`);
  console.log(`  Amount A received: ${removeResult.amountAReceived}`);
  console.log(`  Amount B received: ${removeResult.amountBReceived}`);

  console.log('');
}

/**
 * Order management
 */
async function orderManagementExample(dex: SynorDex): Promise<void> {
  console.log('=== Order Management ===');

  // Get open orders
  const openOrders = await dex.orders.getOpenOrders('SYN-USDT');
  console.log(`Open orders: ${openOrders.length}`);
  for (const order of openOrders) {
    console.log(`  ${order.orderId}: ${order.side} ${order.quantity} @ $${order.price}`);
  }

  // Get order history
  const history = await dex.orders.getOrderHistory({
    symbol: 'SYN-USDT',
    limit: 5,
  });
  console.log(`\nOrder history (last 5):`);
  for (const order of history) {
    console.log(`  ${order.orderId}: ${order.side} ${order.quantity} ${order.status}`);
  }

  // Get specific order
  if (openOrders.length > 0) {
    const order = await dex.orders.getOrder(openOrders[0].orderId);
    console.log(`\nOrder details:`);
    console.log(`  Symbol: ${order.symbol}`);
    console.log(`  Type: ${order.type}`);
    console.log(`  Side: ${order.side}`);
    console.log(`  Quantity: ${order.quantity}`);
    console.log(`  Filled: ${order.executedQty}`);
    console.log(`  Status: ${order.status}`);
  }

  // Cancel a specific order
  if (openOrders.length > 0) {
    console.log('\nCancelling order...');
    const cancelled = await dex.orders.cancelOrder(openOrders[0].orderId);
    console.log(`Order ${cancelled.orderId} cancelled`);
  }

  // Cancel all orders for a symbol
  console.log('\nCancelling all SYN-USDT orders...');
  const cancelledOrders = await dex.orders.cancelAllOrders('SYN-USDT');
  console.log(`Cancelled ${cancelledOrders.length} orders`);

  // Get trade history
  const trades = await dex.orders.getTradeHistory({
    symbol: 'SYN-USDT',
    limit: 5,
  });
  console.log(`\nTrade history (last 5):`);
  for (const trade of trades) {
    console.log(`  ${trade.side} ${trade.quantity} @ $${trade.price} (fee: $${trade.fee})`);
  }

  console.log('');
}

/**
 * Account information
 */
async function accountExample(dex: SynorDex): Promise<void> {
  console.log('=== Account Information ===');

  // Get account balances
  const balances = await dex.account.getBalances();
  console.log('Balances:');
  for (const balance of balances.filter(b => parseFloat(b.total) > 0)) {
    console.log(`  ${balance.asset}: ${balance.free} free, ${balance.locked} locked`);
  }

  // Get account summary
  const summary = await dex.account.getSummary();
  console.log(`\nAccount summary:`);
  console.log(`  Total equity: $${summary.totalEquity}`);
  console.log(`  Available margin: $${summary.availableMargin}`);
  console.log(`  Used margin: $${summary.usedMargin}`);
  console.log(`  Margin level: ${summary.marginLevel}%`);
  console.log(`  Unrealized PnL: $${summary.unrealizedPnl}`);

  // Get deposit address
  const depositAddr = await dex.account.getDepositAddress('SYN');
  console.log(`\nDeposit address for SYN: ${depositAddr.address}`);

  // Get deposit/withdrawal history
  const deposits = await dex.account.getDepositHistory({ limit: 3 });
  console.log(`\nRecent deposits:`);
  for (const dep of deposits) {
    console.log(`  ${dep.asset}: ${dep.amount} (${dep.status})`);
  }

  const withdrawals = await dex.account.getWithdrawalHistory({ limit: 3 });
  console.log(`\nRecent withdrawals:`);
  for (const wd of withdrawals) {
    console.log(`  ${wd.asset}: ${wd.amount} (${wd.status})`);
  }

  // Get fee rates
  const fees = await dex.account.getFeeRates('SYN-USDT');
  console.log(`\nFee rates for SYN-USDT:`);
  console.log(`  Maker: ${fees.makerRate}%`);
  console.log(`  Taker: ${fees.takerRate}%`);

  console.log('');
}

/**
 * Real-time WebSocket streaming
 */
async function streamingExample(dex: SynorDex): Promise<void> {
  console.log('=== Real-time Streaming ===');

  // Subscribe to ticker updates
  console.log('Subscribing to SYN-USDT ticker...');
  const tickerUnsub = dex.streams.subscribeTicker('SYN-USDT', (ticker) => {
    console.log(`  Ticker: $${ticker.lastPrice} (${ticker.priceChangePercent}%)`);
  });

  // Subscribe to orderbook updates
  console.log('Subscribing to orderbook...');
  const orderbookUnsub = dex.streams.subscribeOrderbook('SYN-USDT', (orderbook) => {
    console.log(`  Best bid: $${orderbook.bids[0]?.price}, Best ask: $${orderbook.asks[0]?.price}`);
  });

  // Subscribe to trades
  console.log('Subscribing to trades...');
  const tradesUnsub = dex.streams.subscribeTrades('SYN-USDT', (trade) => {
    const side = trade.isBuyerMaker ? 'SELL' : 'BUY';
    console.log(`  Trade: ${side} ${trade.quantity} @ $${trade.price}`);
  });

  // Subscribe to user order updates
  console.log('Subscribing to order updates...');
  const orderUnsub = dex.streams.subscribeOrders((order) => {
    console.log(`  Order update: ${order.orderId} ${order.status}`);
  });

  // Subscribe to position updates
  console.log('Subscribing to position updates...');
  const positionUnsub = dex.streams.subscribePositions((position) => {
    console.log(`  Position update: ${position.symbol} PnL: $${position.unrealizedPnl}`);
  });

  // Wait for some updates
  console.log('\nListening for 5 seconds...');
  await new Promise(resolve => setTimeout(resolve, 5000));

  // Unsubscribe
  tickerUnsub();
  orderbookUnsub();
  tradesUnsub();
  orderUnsub();
  positionUnsub();
  console.log('Unsubscribed from all streams');

  console.log('');
}

// Run examples
main().catch(console.error);
