//! Synor DEX SDK Examples for Rust
//!
//! Demonstrates decentralized exchange operations:
//! - Spot trading (limit/market orders)
//! - Perpetual futures trading
//! - Liquidity provision (AMM pools)
//! - Order book management
//! - Portfolio tracking

use std::env;
use synor_dex::{
    AddLiquidityRequest, DexConfig, OrderRequest, OrderSide, OrderType, PerpsOrderRequest,
    RemoveLiquidityRequest, SynorDex, TimeInForce,
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize client
    let config = DexConfig {
        api_key: env::var("SYNOR_API_KEY").unwrap_or_else(|_| "your-api-key".to_string()),
        endpoint: "https://dex.synor.io/v1".to_string(),
        timeout: 30000,
        retries: 3,
        debug: false,
        default_market: "SYN-USDC".to_string(),
    };

    let dex = SynorDex::new(config)?;

    // Check service health
    let healthy = dex.health_check().await?;
    println!("Service healthy: {}\n", healthy);

    // Run examples
    markets_example(&dex).await?;
    spot_trading_example(&dex).await?;
    perps_trading_example(&dex).await?;
    liquidity_example(&dex).await?;
    orderbook_example(&dex).await?;
    portfolio_example(&dex).await?;

    dex.close().await?;
    Ok(())
}

async fn markets_example(dex: &SynorDex) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Markets ===");

    // Get all markets
    let markets = dex.markets.list().await?;
    println!("Available markets: {}", markets.len());

    for market in markets.iter().take(5) {
        println!("\n  {}:", market.symbol);
        println!("    Base: {}, Quote: {}", market.base_asset, market.quote_asset);
        println!("    Price: {}", market.last_price);
        println!("    24h Volume: {}", market.volume_24h);
        println!("    24h Change: {}%", market.change_24h);
        println!("    Status: {}", market.status);
    }

    // Get specific market
    let market = dex.markets.get("SYN-USDC").await?;
    println!("\nSYN-USDC details:");
    println!("  Min order size: {}", market.min_order_size);
    println!("  Tick size: {}", market.tick_size);
    println!("  Maker fee: {}%", market.maker_fee);
    println!("  Taker fee: {}%", market.taker_fee);

    // Get market statistics
    let stats = dex.markets.get_stats("SYN-USDC").await?;
    println!("\nMarket statistics:");
    println!("  High 24h: {}", stats.high_24h);
    println!("  Low 24h: {}", stats.low_24h);
    println!("  Open interest: {}", stats.open_interest);
    println!("  Funding rate: {}%", stats.funding_rate);

    println!();
    Ok(())
}

async fn spot_trading_example(dex: &SynorDex) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Spot Trading ===");

    // Place a limit order
    println!("Placing limit buy order...");
    let limit_order = dex
        .spot
        .place_order(OrderRequest {
            market: "SYN-USDC".to_string(),
            side: OrderSide::Buy,
            order_type: OrderType::Limit,
            price: Some("1.50".to_string()),
            quantity: "100".to_string(),
            time_in_force: Some(TimeInForce::GTC),
        })
        .await?;

    println!("Limit order placed:");
    println!("  Order ID: {}", limit_order.order_id);
    println!("  Status: {}", limit_order.status);
    println!("  Price: {}", limit_order.price.unwrap_or_default());
    println!("  Quantity: {}", limit_order.quantity);

    // Place a market order
    println!("\nPlacing market sell order...");
    let market_order = dex
        .spot
        .place_order(OrderRequest {
            market: "SYN-USDC".to_string(),
            side: OrderSide::Sell,
            order_type: OrderType::Market,
            price: None,
            quantity: "50".to_string(),
            time_in_force: None,
        })
        .await?;

    println!("Market order executed:");
    println!("  Order ID: {}", market_order.order_id);
    println!("  Status: {}", market_order.status);
    println!("  Filled: {}", market_order.filled_quantity);
    println!("  Avg price: {}", market_order.average_price.unwrap_or_default());

    // Get order status
    let status = dex.spot.get_order(&limit_order.order_id).await?;
    println!("\nOrder status:");
    println!("  Status: {}", status.status);
    println!("  Filled: {} / {}", status.filled_quantity, status.quantity);
    println!("  Remaining: {}", status.remaining_quantity);

    // Cancel order
    println!("\nCancelling order...");
    dex.spot.cancel_order(&limit_order.order_id).await?;
    println!("Order cancelled successfully");

    // Get open orders
    let open_orders = dex.spot.get_open_orders("SYN-USDC").await?;
    println!("\nOpen orders: {}", open_orders.len());

    // Get trade history
    let trades = dex.spot.get_trade_history("SYN-USDC", 10).await?;
    println!("\nRecent trades: {}", trades.len());
    for trade in trades.iter().take(3) {
        println!("  {:?} {} @ {} ({})", trade.side, trade.quantity, trade.price, trade.timestamp);
    }

    println!();
    Ok(())
}

async fn perps_trading_example(dex: &SynorDex) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Perpetual Futures Trading ===");

    // Get available perps markets
    let perps_markets = dex.perps.list_markets().await?;
    println!("Available perps markets: {}", perps_markets.len());

    for market in perps_markets.iter().take(3) {
        println!(
            "  {}: {} (funding: {}%)",
            market.symbol, market.mark_price, market.funding_rate
        );
    }

    // Open a long position
    println!("\nOpening long position...");
    let position = dex
        .perps
        .open_position(PerpsOrderRequest {
            market: "SYN-USDC-PERP".to_string(),
            side: OrderSide::Buy,
            order_type: OrderType::Limit,
            price: Some("1.50".to_string()),
            size: "1000".to_string(),
            leverage: 10,
            reduce_only: false,
        })
        .await?;

    println!("Position opened:");
    println!("  Position ID: {}", position.position_id);
    println!("  Size: {}", position.size);
    println!("  Entry price: {}", position.entry_price);
    println!("  Leverage: {}x", position.leverage);
    println!("  Liquidation price: {}", position.liquidation_price);

    // Get position details
    let details = dex.perps.get_position(&position.position_id).await?;
    println!("\nPosition details:");
    println!("  Unrealized PnL: {}", details.unrealized_pnl);
    println!("  Margin: {}", details.margin);
    println!("  Margin ratio: {}%", details.margin_ratio);

    // Set stop loss and take profit
    println!("\nSetting stop loss and take profit...");
    dex.perps
        .set_stop_loss(&position.position_id, "1.40")
        .await?;
    println!("Stop loss set at 1.40");

    dex.perps
        .set_take_profit(&position.position_id, "1.80")
        .await?;
    println!("Take profit set at 1.80");

    // Close position
    println!("\nClosing position...");
    let close_result = dex.perps.close_position(&position.position_id).await?;
    println!("Position closed:");
    println!("  Realized PnL: {}", close_result.realized_pnl);
    println!("  Close price: {}", close_result.close_price);

    // Get all positions
    let positions = dex.perps.get_positions().await?;
    println!("\nOpen positions: {}", positions.len());

    // Get funding history
    let funding = dex.perps.get_funding_history("SYN-USDC-PERP", 10).await?;
    println!("Funding payments: {}", funding.len());

    println!();
    Ok(())
}

async fn liquidity_example(dex: &SynorDex) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Liquidity Provision ===");

    // Get available pools
    let pools = dex.liquidity.list_pools().await?;
    println!("Available pools: {}", pools.len());

    for pool in pools.iter().take(3) {
        println!("\n  {}:", pool.name);
        println!("    TVL: ${}", pool.tvl);
        println!("    APR: {}%", pool.apr);
        println!("    Volume 24h: ${}", pool.volume_24h);
        println!("    Fee tier: {}%", pool.fee_tier);
    }

    // Get pool details
    let pool = dex.liquidity.get_pool("SYN-USDC").await?;
    println!("\nSYN-USDC pool details:");
    println!("  Token0: {} ({})", pool.token0.symbol, pool.token0_reserve);
    println!("  Token1: {} ({})", pool.token1.symbol, pool.token1_reserve);
    println!("  Price: {}", pool.price);
    println!("  Total LP tokens: {}", pool.total_lp_tokens);

    // Add liquidity
    println!("\nAdding liquidity...");
    let add_result = dex
        .liquidity
        .add_liquidity(AddLiquidityRequest {
            pool: "SYN-USDC".to_string(),
            amount0: "100".to_string(),
            amount1: "150".to_string(),
            slippage_bps: 50, // 0.5%
        })
        .await?;

    println!("Liquidity added:");
    println!("  LP tokens received: {}", add_result.lp_tokens);
    println!("  Position ID: {}", add_result.position_id);
    println!("  Share of pool: {}%", add_result.share_of_pool);

    // Get LP positions
    let lp_positions = dex.liquidity.get_positions().await?;
    println!("\nLP positions: {}", lp_positions.len());
    for pos in &lp_positions {
        println!("  {}: {} LP tokens (value: ${})", pos.pool, pos.lp_tokens, pos.value);
    }

    // Claim fees
    println!("\nClaiming fees...");
    let fees = dex.liquidity.claim_fees(&add_result.position_id).await?;
    println!("Fees claimed:");
    println!("  Token0: {}", fees.amount0);
    println!("  Token1: {}", fees.amount1);

    // Remove liquidity
    println!("\nRemoving liquidity...");
    let remove_result = dex
        .liquidity
        .remove_liquidity(RemoveLiquidityRequest {
            position_id: add_result.position_id.clone(),
            lp_tokens: add_result.lp_tokens.clone(),
            slippage_bps: 50,
        })
        .await?;

    println!("Liquidity removed:");
    println!("  Token0 received: {}", remove_result.amount0);
    println!("  Token1 received: {}", remove_result.amount1);

    println!();
    Ok(())
}

async fn orderbook_example(dex: &SynorDex) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Order Book ===");

    // Get order book snapshot
    let orderbook = dex.orderbook.get_snapshot("SYN-USDC", 10).await?;

    println!("Order book for SYN-USDC:");
    println!("\nAsks (sells):");
    for ask in orderbook.asks.iter().take(5) {
        println!("  {} @ {}", ask.quantity, ask.price);
    }

    println!("\nBids (buys):");
    for bid in orderbook.bids.iter().take(5) {
        println!("  {} @ {}", bid.quantity, bid.price);
    }

    println!("\nSpread: {} ({}%)", orderbook.spread, orderbook.spread_percent);
    println!("Mid price: {}", orderbook.mid_price);

    // Get recent trades
    let recent_trades = dex.orderbook.get_recent_trades("SYN-USDC", 10).await?;
    println!("\nRecent trades:");
    for trade in recent_trades.iter().take(5) {
        println!("  {:?} {} @ {}", trade.side, trade.quantity, trade.price);
    }

    // Subscribe to orderbook updates (simulated)
    println!("\nSubscribing to orderbook updates...");
    let mut updates = dex.orderbook.subscribe("SYN-USDC").await?;

    // Process a few updates
    tokio::spawn(async move {
        for _ in 0..3 {
            if let Some(update) = updates.recv().await {
                println!("  Update: {:?} {} @ {}", update.side, update.quantity, update.price);
            }
        }
    });

    tokio::time::sleep(std::time::Duration::from_secs(2)).await;

    println!();
    Ok(())
}

async fn portfolio_example(dex: &SynorDex) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Portfolio ===");

    // Get portfolio overview
    let portfolio = dex.portfolio.get_overview().await?;

    println!("Portfolio overview:");
    println!("  Total value: ${}", portfolio.total_value);
    println!("  Available balance: ${}", portfolio.available_balance);
    println!("  In orders: ${}", portfolio.in_orders);
    println!("  In positions: ${}", portfolio.in_positions);
    println!("  Unrealized PnL: ${}", portfolio.unrealized_pnl);

    // Get balances
    let balances = dex.portfolio.get_balances().await?;
    println!("\nBalances:");
    for balance in &balances {
        println!(
            "  {}: {} (available: {}, in orders: {})",
            balance.asset, balance.total, balance.available, balance.in_orders
        );
    }

    // Get PnL history
    let pnl_history = dex.portfolio.get_pnl_history(30).await?; // Last 30 days
    println!("\nPnL history (last {} days):", pnl_history.len());
    if let Some(last) = pnl_history.last() {
        println!("  Total PnL: ${}", last.cumulative_pnl);
    }

    // Get trade statistics
    let stats = dex.portfolio.get_stats().await?;
    println!("\nTrade statistics:");
    println!("  Total trades: {}", stats.total_trades);
    println!("  Win rate: {}%", stats.win_rate);
    println!("  Avg profit: ${}", stats.avg_profit);
    println!("  Avg loss: ${}", stats.avg_loss);
    println!("  Best trade: ${}", stats.best_trade);
    println!("  Worst trade: ${}", stats.worst_trade);

    println!();
    Ok(())
}
