#!/usr/bin/env python3
"""
Synor DEX SDK Examples for Python

Demonstrates decentralized exchange operations:
- Spot trading (market/limit orders)
- Perpetual futures trading
- Liquidity provision
- Order management
- Real-time market data
"""

import asyncio
import os
from synor_dex import (
    SynorDex,
    DexConfig,
    Network,
    OrderSide,
    OrderType,
    TimeInForce,
    PositionSide,
    MarginType,
)


async def main():
    """Main entry point."""
    # Initialize client
    config = DexConfig(
        api_key=os.environ.get("SYNOR_API_KEY", "your-api-key"),
        endpoint="https://dex.synor.io/v1",
        ws_endpoint="wss://dex.synor.io/v1/ws",
        timeout=30000,
        retries=3,
        debug=False,
        default_network=Network.MAINNET,
    )

    dex = SynorDex(config)

    try:
        # Check service health
        healthy = await dex.health_check()
        print(f"Service healthy: {healthy}\n")

        # Example 1: Market data
        await market_data_example(dex)

        # Example 2: Spot trading
        await spot_trading_example(dex)

        # Example 3: Perpetual futures
        await perpetual_futures_example(dex)

        # Example 4: Liquidity provision
        await liquidity_example(dex)

        # Example 5: Order management
        await order_management_example(dex)

        # Example 6: Account information
        await account_example(dex)

        # Example 7: Real-time streaming
        await streaming_example(dex)
    finally:
        await dex.close()


async def market_data_example(dex: SynorDex):
    """Market data and orderbook."""
    print("=== Market Data ===")

    # Get all trading pairs
    pairs = await dex.markets.get_pairs()
    print(f"Available trading pairs: {len(pairs)}")
    for pair in pairs[:5]:
        print(f"  {pair.symbol}: {pair.base_asset}/{pair.quote_asset}")

    # Get ticker for a specific pair
    ticker = await dex.markets.get_ticker("SYN-USDT")
    print(f"\nSYN-USDT Ticker:")
    print(f"  Last price: ${ticker.last_price}")
    print(f"  24h change: {ticker.price_change_percent}%")
    print(f"  24h high: ${ticker.high_price}")
    print(f"  24h low: ${ticker.low_price}")
    print(f"  24h volume: {ticker.volume} SYN")
    print(f"  24h quote volume: ${ticker.quote_volume}")

    # Get orderbook
    orderbook = await dex.markets.get_orderbook("SYN-USDT", depth=10)
    print(f"\nOrderbook (top 5):")
    print("  Bids:")
    for bid in orderbook.bids[:5]:
        print(f"    ${bid.price} - {bid.quantity} SYN")
    print("  Asks:")
    for ask in orderbook.asks[:5]:
        print(f"    ${ask.price} - {ask.quantity} SYN")

    # Get recent trades
    trades = await dex.markets.get_trades("SYN-USDT", limit=5)
    print(f"\nRecent trades:")
    for trade in trades:
        side = "SELL" if trade.is_buyer_maker else "BUY"
        print(f"  {side} {trade.quantity} @ ${trade.price}")

    # Get OHLCV candles
    candles = await dex.markets.get_candles("SYN-USDT", interval="1h", limit=5)
    print(f"\nHourly candles:")
    for candle in candles:
        print(f"  {candle.open_time}: O={candle.open} H={candle.high} L={candle.low} C={candle.close}")

    print()


async def spot_trading_example(dex: SynorDex):
    """Spot trading operations."""
    print("=== Spot Trading ===")

    # Place a market buy order
    print("Placing market buy order...")
    market_buy = await dex.spot.create_order(
        symbol="SYN-USDT",
        side=OrderSide.BUY,
        order_type=OrderType.MARKET,
        quantity=10,  # Buy 10 SYN
    )
    print(f"Market buy order: {market_buy.order_id}")
    print(f"  Status: {market_buy.status}")
    print(f"  Filled: {market_buy.executed_qty} SYN")
    print(f"  Avg price: ${market_buy.avg_price}")

    # Place a limit sell order
    print("\nPlacing limit sell order...")
    limit_sell = await dex.spot.create_order(
        symbol="SYN-USDT",
        side=OrderSide.SELL,
        order_type=OrderType.LIMIT,
        quantity=5,
        price=15.50,  # Sell at $15.50
        time_in_force=TimeInForce.GTC,  # Good till cancelled
    )
    print(f"Limit sell order: {limit_sell.order_id}")
    print(f"  Price: ${limit_sell.price}")
    print(f"  Status: {limit_sell.status}")

    # Place a stop-loss order
    print("\nPlacing stop-loss order...")
    stop_loss = await dex.spot.create_order(
        symbol="SYN-USDT",
        side=OrderSide.SELL,
        order_type=OrderType.STOP_LOSS,
        quantity=10,
        stop_price=12.00,  # Trigger at $12.00
    )
    print(f"Stop-loss order: {stop_loss.order_id}")
    print(f"  Stop price: ${stop_loss.stop_price}")

    # Place a take-profit limit order
    print("\nPlacing take-profit order...")
    take_profit = await dex.spot.create_order(
        symbol="SYN-USDT",
        side=OrderSide.SELL,
        order_type=OrderType.TAKE_PROFIT_LIMIT,
        quantity=10,
        price=20.00,  # Sell at $20.00
        stop_price=19.50,  # Trigger at $19.50
        time_in_force=TimeInForce.GTC,
    )
    print(f"Take-profit order: {take_profit.order_id}")

    print()


async def perpetual_futures_example(dex: SynorDex):
    """Perpetual futures trading."""
    print("=== Perpetual Futures ===")

    # Get perpetual markets
    markets = await dex.perpetuals.get_markets()
    print(f"Available perpetual markets: {len(markets)}")
    for market in markets[:3]:
        print(f"  {market.symbol}: {market.max_leverage}x max leverage, {market.maintenance_margin_rate}% MMR")

    # Get funding rate
    funding = await dex.perpetuals.get_funding_rate("SYN-USDT-PERP")
    print(f"\nFunding rate for SYN-USDT-PERP:")
    print(f"  Current rate: {funding.funding_rate * 100:.4f}%")
    print(f"  Predicted rate: {funding.predicted_rate * 100:.4f}%")
    print(f"  Next funding: {funding.next_funding_time}")

    # Set leverage
    await dex.perpetuals.set_leverage("SYN-USDT-PERP", 10)
    print("\nLeverage set to 10x")

    # Set margin type (isolated/cross)
    await dex.perpetuals.set_margin_type("SYN-USDT-PERP", MarginType.ISOLATED)
    print("Margin type set to Isolated")

    # Open a long position
    print("\nOpening long position...")
    long_order = await dex.perpetuals.create_order(
        symbol="SYN-USDT-PERP",
        side=OrderSide.BUY,
        position_side=PositionSide.LONG,
        order_type=OrderType.MARKET,
        quantity=100,  # 100 contracts
    )
    print(f"Long position opened: {long_order.order_id}")
    print(f"  Entry price: ${long_order.avg_price}")
    print(f"  Position size: {long_order.executed_qty} contracts")

    # Set stop-loss and take-profit
    print("\nSetting SL/TP...")
    await dex.perpetuals.create_order(
        symbol="SYN-USDT-PERP",
        side=OrderSide.SELL,
        position_side=PositionSide.LONG,
        order_type=OrderType.STOP_MARKET,
        quantity=100,
        stop_price=12.00,  # Stop-loss at $12
        reduce_only=True,
    )
    print("  Stop-loss set at $12.00")

    await dex.perpetuals.create_order(
        symbol="SYN-USDT-PERP",
        side=OrderSide.SELL,
        position_side=PositionSide.LONG,
        order_type=OrderType.TAKE_PROFIT_MARKET,
        quantity=100,
        stop_price=18.00,  # Take-profit at $18
        reduce_only=True,
    )
    print("  Take-profit set at $18.00")

    # Get position info
    positions = await dex.perpetuals.get_positions("SYN-USDT-PERP")
    for pos in positions:
        print(f"\nPosition info:")
        print(f"  Symbol: {pos.symbol}")
        print(f"  Side: {pos.position_side}")
        print(f"  Size: {pos.position_amount} contracts")
        print(f"  Entry: ${pos.entry_price}")
        print(f"  Mark: ${pos.mark_price}")
        print(f"  PnL: ${pos.unrealized_pnl} ({pos.unrealized_pnl_percent}%)")
        print(f"  Leverage: {pos.leverage}x")
        print(f"  Liq. price: ${pos.liquidation_price}")

    # Close position
    print("\nClosing position...")
    await dex.perpetuals.close_position("SYN-USDT-PERP", PositionSide.LONG)
    print("Position closed")

    print()


async def liquidity_example(dex: SynorDex):
    """Liquidity provision."""
    print("=== Liquidity Provision ===")

    # Get available pools
    pools = await dex.liquidity.get_pools()
    print(f"Available liquidity pools: {len(pools)}")
    for pool in pools[:3]:
        print(f"  {pool.name}:")
        print(f"    TVL: ${pool.tvl:,.0f}")
        print(f"    APY: {pool.apy:.2f}%")
        print(f"    Fee tier: {pool.fee_tier}%")

    # Get pool details
    pool = await dex.liquidity.get_pool("SYN-USDT")
    print(f"\nSYN-USDT Pool details:")
    print(f"  Reserve A: {pool.reserve_a} SYN")
    print(f"  Reserve B: {pool.reserve_b} USDT")
    print(f"  Total shares: {pool.total_shares}")
    print(f"  Your shares: {pool.user_shares}")

    # Add liquidity
    print("\nAdding liquidity...")
    add_result = await dex.liquidity.add_liquidity(
        pool_id="SYN-USDT",
        amount_a=100,  # 100 SYN
        amount_b=1400,  # 1400 USDT
        slippage_tolerance=0.5,  # 0.5% slippage
    )
    print(f"Liquidity added:")
    print(f"  Shares received: {add_result.shares_received}")
    print(f"  Amount A deposited: {add_result.amount_a_deposited}")
    print(f"  Amount B deposited: {add_result.amount_b_deposited}")

    # Get LP positions
    lp_positions = await dex.liquidity.get_positions()
    print(f"\nYour LP positions:")
    for lp in lp_positions:
        print(f"  {lp.pool_id}: {lp.shares} shares (${lp.value_usd})")
        print(f"    Fees earned: ${lp.fees_earned}")

    # Remove liquidity
    print("\nRemoving liquidity...")
    remove_result = await dex.liquidity.remove_liquidity(
        pool_id="SYN-USDT",
        shares=add_result.shares_received * 0.5,  # Remove 50%
        slippage_tolerance=0.5,
    )
    print(f"Liquidity removed:")
    print(f"  Amount A received: {remove_result.amount_a_received}")
    print(f"  Amount B received: {remove_result.amount_b_received}")

    print()


async def order_management_example(dex: SynorDex):
    """Order management."""
    print("=== Order Management ===")

    # Get open orders
    open_orders = await dex.orders.get_open_orders("SYN-USDT")
    print(f"Open orders: {len(open_orders)}")
    for order in open_orders:
        print(f"  {order.order_id}: {order.side} {order.quantity} @ ${order.price}")

    # Get order history
    history = await dex.orders.get_order_history(symbol="SYN-USDT", limit=5)
    print(f"\nOrder history (last 5):")
    for order in history:
        print(f"  {order.order_id}: {order.side} {order.quantity} {order.status}")

    # Get specific order
    if open_orders:
        order = await dex.orders.get_order(open_orders[0].order_id)
        print(f"\nOrder details:")
        print(f"  Symbol: {order.symbol}")
        print(f"  Type: {order.order_type}")
        print(f"  Side: {order.side}")
        print(f"  Quantity: {order.quantity}")
        print(f"  Filled: {order.executed_qty}")
        print(f"  Status: {order.status}")

    # Cancel a specific order
    if open_orders:
        print("\nCancelling order...")
        cancelled = await dex.orders.cancel_order(open_orders[0].order_id)
        print(f"Order {cancelled.order_id} cancelled")

    # Cancel all orders for a symbol
    print("\nCancelling all SYN-USDT orders...")
    cancelled_orders = await dex.orders.cancel_all_orders("SYN-USDT")
    print(f"Cancelled {len(cancelled_orders)} orders")

    # Get trade history
    trades = await dex.orders.get_trade_history(symbol="SYN-USDT", limit=5)
    print(f"\nTrade history (last 5):")
    for trade in trades:
        print(f"  {trade.side} {trade.quantity} @ ${trade.price} (fee: ${trade.fee})")

    print()


async def account_example(dex: SynorDex):
    """Account information."""
    print("=== Account Information ===")

    # Get account balances
    balances = await dex.account.get_balances()
    print("Balances:")
    for balance in balances:
        if float(balance.total) > 0:
            print(f"  {balance.asset}: {balance.free} free, {balance.locked} locked")

    # Get account summary
    summary = await dex.account.get_summary()
    print(f"\nAccount summary:")
    print(f"  Total equity: ${summary.total_equity}")
    print(f"  Available margin: ${summary.available_margin}")
    print(f"  Used margin: ${summary.used_margin}")
    print(f"  Margin level: {summary.margin_level}%")
    print(f"  Unrealized PnL: ${summary.unrealized_pnl}")

    # Get deposit address
    deposit_addr = await dex.account.get_deposit_address("SYN")
    print(f"\nDeposit address for SYN: {deposit_addr.address}")

    # Get deposit/withdrawal history
    deposits = await dex.account.get_deposit_history(limit=3)
    print(f"\nRecent deposits:")
    for dep in deposits:
        print(f"  {dep.asset}: {dep.amount} ({dep.status})")

    withdrawals = await dex.account.get_withdrawal_history(limit=3)
    print(f"\nRecent withdrawals:")
    for wd in withdrawals:
        print(f"  {wd.asset}: {wd.amount} ({wd.status})")

    # Get fee rates
    fees = await dex.account.get_fee_rates("SYN-USDT")
    print(f"\nFee rates for SYN-USDT:")
    print(f"  Maker: {fees.maker_rate}%")
    print(f"  Taker: {fees.taker_rate}%")

    print()


async def streaming_example(dex: SynorDex):
    """Real-time WebSocket streaming."""
    print("=== Real-time Streaming ===")

    received_count = 0

    def on_ticker(ticker):
        nonlocal received_count
        received_count += 1
        print(f"  Ticker: ${ticker.last_price} ({ticker.price_change_percent}%)")

    def on_orderbook(orderbook):
        print(f"  Best bid: ${orderbook.bids[0].price if orderbook.bids else 'N/A'}, "
              f"Best ask: ${orderbook.asks[0].price if orderbook.asks else 'N/A'}")

    def on_trade(trade):
        side = "SELL" if trade.is_buyer_maker else "BUY"
        print(f"  Trade: {side} {trade.quantity} @ ${trade.price}")

    # Subscribe to ticker updates
    print("Subscribing to SYN-USDT ticker...")
    ticker_unsub = await dex.streams.subscribe_ticker("SYN-USDT", on_ticker)

    # Subscribe to orderbook updates
    print("Subscribing to orderbook...")
    orderbook_unsub = await dex.streams.subscribe_orderbook("SYN-USDT", on_orderbook)

    # Subscribe to trades
    print("Subscribing to trades...")
    trades_unsub = await dex.streams.subscribe_trades("SYN-USDT", on_trade)

    # Wait for some updates
    print("\nListening for 5 seconds...")
    await asyncio.sleep(5)

    # Unsubscribe
    await ticker_unsub()
    await orderbook_unsub()
    await trades_unsub()
    print(f"Unsubscribed from all streams. Received {received_count} ticker updates.")

    print()


if __name__ == "__main__":
    asyncio.run(main())
