# frozen_string_literal: true

#
# Synor DEX SDK Examples for Ruby
#
# Demonstrates decentralized exchange operations:
# - Market data and orderbook queries
# - Spot trading (limit and market orders)
# - Perpetual futures trading
# - Liquidity provision (AMM)
# - Portfolio management
#

require 'synor/dex'

class DexExample
  def initialize(dex)
    @dex = dex
  end

  def run_markets_example
    puts '=== Market Information ==='

    # List all available markets
    markets = @dex.markets.list
    puts "Available markets: #{markets.length}"
    markets.first(5).each do |market|
      puts "  #{market.symbol}: #{market.base_asset}/#{market.quote_asset} (#{market.status})"
    end

    # Get specific market details
    eth_usdc = @dex.markets.get('ETH-USDC')
    puts "\n#{eth_usdc.symbol} market:"
    puts "  Price: $#{format('%.2f', eth_usdc.last_price)}"
    puts "  24h Change: #{format('%.2f', eth_usdc.change_24h)}%"
    puts "  24h Volume: $#{eth_usdc.volume_24h.to_i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse}"
    puts "  24h High: $#{format('%.2f', eth_usdc.high_24h)}"
    puts "  24h Low: $#{format('%.2f', eth_usdc.low_24h)}"

    # Get orderbook
    orderbook = @dex.markets.get_orderbook('ETH-USDC', depth: 10)
    puts "\nOrderbook (#{orderbook.bids.length} bids, #{orderbook.asks.length} asks):"
    puts "  Best bid: $#{format('%.2f', orderbook.bids.first.price)} (#{format('%.4f', orderbook.bids.first.quantity)} ETH)"
    puts "  Best ask: $#{format('%.2f', orderbook.asks.first.price)} (#{format('%.4f', orderbook.asks.first.quantity)} ETH)"
    puts "  Spread: $#{format('%.2f', orderbook.spread)} (#{format('%.3f', orderbook.spread_percent)}%)"

    # Get recent trades
    trades = @dex.markets.get_trades('ETH-USDC', limit: 5)
    puts "\nRecent trades:"
    trades.each do |trade|
      puts "  #{trade.side}: #{format('%.4f', trade.quantity)} @ $#{format('%.2f', trade.price)}"
    end
    puts
  end

  def run_spot_trading_example
    puts '=== Spot Trading ==='

    # Get account balance
    balances = @dex.account.get_balances
    puts 'Account balances:'
    balances.select { |b| b.total.positive? }.each do |balance|
      puts "  #{balance.asset}: #{format('%.4f', balance.available)} available, #{format('%.4f', balance.locked)} locked"
    end

    # Place a limit buy order
    puts "\nPlacing limit buy order..."
    limit_order = @dex.spot.place_order(
      symbol: 'ETH-USDC',
      side: :buy,
      type: :limit,
      quantity: 0.1,
      price: 3000.00,
      time_in_force: :gtc
    )

    puts 'Limit order placed:'
    puts "  Order ID: #{limit_order.order_id}"
    puts "  Status: #{limit_order.status}"
    puts "  Price: $#{format('%.2f', limit_order.price)}"
    puts "  Quantity: #{format('%.4f', limit_order.quantity)}"

    # Place a market sell order
    puts "\nPlacing market sell order..."
    market_order = @dex.spot.place_order(
      symbol: 'ETH-USDC',
      side: :sell,
      type: :market,
      quantity: 0.05
    )

    puts 'Market order executed:'
    puts "  Order ID: #{market_order.order_id}"
    puts "  Status: #{market_order.status}"
    puts "  Filled: #{format('%.4f', market_order.filled_quantity)}"
    puts "  Avg price: $#{format('%.2f', market_order.average_price)}"

    # Get open orders
    open_orders = @dex.spot.get_open_orders(symbol: 'ETH-USDC')
    puts "\nOpen orders: #{open_orders.length}"
    open_orders.each do |order|
      puts "  #{order.order_id}: #{order.side} #{format('%.4f', order.quantity)} @ $#{format('%.2f', order.price)}"
    end

    # Cancel an order
    if open_orders.any?
      cancelled = @dex.spot.cancel_order(open_orders.first.order_id)
      puts "\nCancelled order: #{cancelled.order_id}"
    end
    puts
  end

  def run_perps_example
    puts '=== Perpetual Futures ==='

    # Get perpetual markets
    perp_markets = @dex.perps.get_markets
    puts "Perpetual markets: #{perp_markets.length}"
    perp_markets.first(3).each do |market|
      puts "  #{market.symbol}: Mark $#{format('%.2f', market.mark_price)}, Funding #{format('%.4f', market.funding_rate)}%"
    end

    # Get account position
    positions = @dex.perps.get_positions
    puts "\nOpen positions: #{positions.length}"
    positions.each do |position|
      puts "  #{position.symbol}: #{position.side} #{format('%.4f', position.size)}"
      puts "    Entry: $#{format('%.2f', position.entry_price)}, PnL: $#{format('%.2f', position.unrealized_pnl)}"
    end

    # Open a long position
    puts "\nOpening long position..."
    long_order = @dex.perps.place_order(
      symbol: 'BTC-USDC-PERP',
      side: :buy,
      type: :limit,
      quantity: 0.01,
      price: 95_000.00,
      leverage: 10,
      reduce_only: false
    )

    puts 'Position order placed:'
    puts "  Order ID: #{long_order.order_id}"
    puts "  Leverage: #{long_order.leverage}x"
    puts "  Margin: $#{format('%.2f', long_order.required_margin)}"

    # Set stop-loss and take-profit
    puts "\nSetting SL/TP..."
    @dex.perps.set_stop_loss('BTC-USDC-PERP', 90_000.00)
    @dex.perps.set_take_profit('BTC-USDC-PERP', 100_000.00)
    puts '  Stop loss: $90,000'
    puts '  Take profit: $100,000'

    # Get funding rate history
    funding_history = @dex.perps.get_funding_history('BTC-USDC-PERP', limit: 5)
    puts "\nFunding rate history:"
    funding_history.each do |funding|
      puts "  #{funding.timestamp}: #{format('%.4f', funding.rate)}%"
    end
    puts
  end

  def run_liquidity_example
    puts '=== Liquidity Provision ==='

    # Get available pools
    pools = @dex.liquidity.get_pools
    puts "Liquidity pools: #{pools.length}"
    pools.first(5).each do |pool|
      tvl = pool.total_value_locked.to_i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
      puts "  #{pool.name}: TVL $#{tvl}, APR #{format('%.2f', pool.apr)}%"
    end

    # Get pool details
    eth_usdc_pool = @dex.liquidity.get_pool('ETH-USDC')
    tvl = eth_usdc_pool.total_value_locked.to_i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
    vol = eth_usdc_pool.volume_24h.to_i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
    puts "\n#{eth_usdc_pool.name} pool:"
    puts "  TVL: $#{tvl}"
    puts "  Volume 24h: $#{vol}"
    puts "  Fee tier: #{format('%.2f', eth_usdc_pool.fee_tier)}%"
    puts "  APR: #{format('%.2f', eth_usdc_pool.apr)}%"
    puts "  Reserve A: #{format('%.4f', eth_usdc_pool.reserve_a)} ETH"
    puts "  Reserve B: #{format('%.2f', eth_usdc_pool.reserve_b)} USDC"

    # Add liquidity
    puts "\nAdding liquidity..."
    add_result = @dex.liquidity.add_liquidity(
      pool_id: 'ETH-USDC',
      amount_a: 0.1,
      amount_b: 300.0,
      slippage_tolerance: 0.5
    )

    puts 'Liquidity added:'
    puts "  LP tokens received: #{format('%.8f', add_result.lp_tokens_received)}"
    puts "  Share of pool: #{format('%.4f', add_result.share_of_pool)}%"

    # Get LP positions
    lp_positions = @dex.liquidity.get_positions
    puts "\nLP positions: #{lp_positions.length}"
    lp_positions.each do |position|
      puts "  #{position.pool_id}: #{format('%.8f', position.lp_tokens)} tokens, $#{format('%.2f', position.value)}"
      puts "    Earned fees: $#{format('%.2f', position.earned_fees)}"
    end

    # Remove liquidity
    puts "\nRemoving liquidity..."
    remove_result = @dex.liquidity.remove_liquidity(
      pool_id: 'ETH-USDC',
      lp_tokens: add_result.lp_tokens_received,
      slippage_tolerance: 0.5
    )

    puts 'Liquidity removed:'
    puts "  Amount A: #{format('%.4f', remove_result.amount_a)} ETH"
    puts "  Amount B: #{format('%.2f', remove_result.amount_b)} USDC"
    puts
  end

  def run_portfolio_example
    puts '=== Portfolio Management ==='

    # Get portfolio summary
    portfolio = @dex.portfolio.get_summary
    puts 'Portfolio summary:'
    puts "  Total value: $#{format('%.2f', portfolio.total_value)}"
    puts "  Available: $#{format('%.2f', portfolio.available_balance)}"
    puts "  In orders: $#{format('%.2f', portfolio.in_orders)}"
    puts "  In positions: $#{format('%.2f', portfolio.in_positions)}"
    puts "  Unrealized PnL: $#{format('%.2f', portfolio.unrealized_pnl)}"

    # Get asset allocation
    puts "\nAsset allocation:"
    portfolio.allocations.each do |allocation|
      puts "  #{allocation.asset}: #{format('%.1f', allocation.percentage)}% ($#{format('%.2f', allocation.value)})"
    end

    # Get trade history
    trade_history = @dex.portfolio.get_trade_history(limit: 10)
    puts "\nRecent trades: #{trade_history.length}"
    trade_history.each do |trade|
      puts "  #{trade.timestamp}: #{trade.side} #{format('%.4f', trade.quantity)} #{trade.symbol} @ $#{format('%.2f', trade.price)}"
    end

    # Get PnL report
    pnl_report = @dex.portfolio.get_pnl_report(:month)
    puts "\nMonthly PnL report:"
    puts "  Realized PnL: $#{format('%.2f', pnl_report.realized_pnl)}"
    puts "  Unrealized PnL: $#{format('%.2f', pnl_report.unrealized_pnl)}"
    puts "  Total fees: $#{format('%.2f', pnl_report.total_fees)}"
    puts "  Net profit: $#{format('%.2f', pnl_report.net_profit)}"
    puts
  end
end

# Main execution
if __FILE__ == $PROGRAM_NAME
  # Initialize client
  api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
  config = Synor::Dex::Config.new(
    api_key: api_key,
    endpoint: 'https://dex.synor.io/v1',
    timeout: 30,
    retries: 3,
    debug: false
  )

  dex = Synor::Dex::Client.new(config)
  example = DexExample.new(dex)

  begin
    # Check service health
    healthy = dex.health_check
    puts "Service healthy: #{healthy}\n\n"

    # Run examples
    example.run_markets_example
    example.run_spot_trading_example
    example.run_perps_example
    example.run_liquidity_example
    example.run_portfolio_example
  rescue StandardError => e
    warn "Error: #{e.message}"
    exit 1
  end
end
