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

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Synor.Dex;

namespace Synor.Examples;

public class DexExample
{
    private readonly SynorDex _dex;

    public DexExample(SynorDex dex)
    {
        _dex = dex;
    }

    public async Task RunMarketsExample()
    {
        Console.WriteLine("=== Market Information ===");

        // List all available markets
        var markets = await _dex.Markets.ListAsync();
        Console.WriteLine($"Available markets: {markets.Count}");
        foreach (var market in markets.GetRange(0, Math.Min(markets.Count, 5)))
        {
            Console.WriteLine($"  {market.Symbol}: {market.BaseAsset}/{market.QuoteAsset} ({market.Status})");
        }

        // Get specific market details
        var ethUsdc = await _dex.Markets.GetAsync("ETH-USDC");
        Console.WriteLine($"\n{ethUsdc.Symbol} market:");
        Console.WriteLine($"  Price: ${ethUsdc.LastPrice:F2}");
        Console.WriteLine($"  24h Change: {ethUsdc.Change24h:F2}%");
        Console.WriteLine($"  24h Volume: ${ethUsdc.Volume24h:N0}");
        Console.WriteLine($"  24h High: ${ethUsdc.High24h:F2}");
        Console.WriteLine($"  24h Low: ${ethUsdc.Low24h:F2}");

        // Get orderbook
        var orderbook = await _dex.Markets.GetOrderbookAsync("ETH-USDC", 10);
        Console.WriteLine($"\nOrderbook ({orderbook.Bids.Count} bids, {orderbook.Asks.Count} asks):");
        Console.WriteLine("  Best bid: ${0:F2} ({1:F4} ETH)", orderbook.Bids[0].Price, orderbook.Bids[0].Quantity);
        Console.WriteLine("  Best ask: ${0:F2} ({1:F4} ETH)", orderbook.Asks[0].Price, orderbook.Asks[0].Quantity);
        Console.WriteLine($"  Spread: ${orderbook.Spread:F2} ({orderbook.SpreadPercent:F3}%)");

        // Get recent trades
        var trades = await _dex.Markets.GetTradesAsync("ETH-USDC", 5);
        Console.WriteLine("\nRecent trades:");
        foreach (var trade in trades)
        {
            Console.WriteLine($"  {trade.Side}: {trade.Quantity:F4} @ ${trade.Price:F2}");
        }
        Console.WriteLine();
    }

    public async Task RunSpotTradingExample()
    {
        Console.WriteLine("=== Spot Trading ===");

        // Get account balance
        var balances = await _dex.Account.GetBalancesAsync();
        Console.WriteLine("Account balances:");
        foreach (var balance in balances)
        {
            if (balance.Total > 0)
            {
                Console.WriteLine($"  {balance.Asset}: {balance.Available:F4} available, {balance.Locked:F4} locked");
            }
        }

        // Place a limit buy order
        Console.WriteLine("\nPlacing limit buy order...");
        var limitOrder = await _dex.Spot.PlaceOrderAsync(new SpotOrderRequest
        {
            Symbol = "ETH-USDC",
            Side = OrderSide.Buy,
            Type = OrderType.Limit,
            Quantity = 0.1m,
            Price = 3000.00m,
            TimeInForce = TimeInForce.GoodTillCancel
        });

        Console.WriteLine($"Limit order placed:");
        Console.WriteLine($"  Order ID: {limitOrder.OrderId}");
        Console.WriteLine($"  Status: {limitOrder.Status}");
        Console.WriteLine($"  Price: ${limitOrder.Price:F2}");
        Console.WriteLine($"  Quantity: {limitOrder.Quantity:F4}");

        // Place a market sell order
        Console.WriteLine("\nPlacing market sell order...");
        var marketOrder = await _dex.Spot.PlaceOrderAsync(new SpotOrderRequest
        {
            Symbol = "ETH-USDC",
            Side = OrderSide.Sell,
            Type = OrderType.Market,
            Quantity = 0.05m
        });

        Console.WriteLine($"Market order executed:");
        Console.WriteLine($"  Order ID: {marketOrder.OrderId}");
        Console.WriteLine($"  Status: {marketOrder.Status}");
        Console.WriteLine($"  Filled: {marketOrder.FilledQuantity:F4}");
        Console.WriteLine($"  Avg price: ${marketOrder.AveragePrice:F2}");

        // Get open orders
        var openOrders = await _dex.Spot.GetOpenOrdersAsync("ETH-USDC");
        Console.WriteLine($"\nOpen orders: {openOrders.Count}");
        foreach (var order in openOrders)
        {
            Console.WriteLine($"  {order.OrderId}: {order.Side} {order.Quantity:F4} @ ${order.Price:F2}");
        }

        // Cancel an order
        if (openOrders.Count > 0)
        {
            var cancelled = await _dex.Spot.CancelOrderAsync(openOrders[0].OrderId);
            Console.WriteLine($"\nCancelled order: {cancelled.OrderId}");
        }
        Console.WriteLine();
    }

    public async Task RunPerpsExample()
    {
        Console.WriteLine("=== Perpetual Futures ===");

        // Get perpetual markets
        var perpMarkets = await _dex.Perps.GetMarketsAsync();
        Console.WriteLine($"Perpetual markets: {perpMarkets.Count}");
        foreach (var market in perpMarkets.GetRange(0, Math.Min(perpMarkets.Count, 3)))
        {
            Console.WriteLine($"  {market.Symbol}: Mark ${market.MarkPrice:F2}, Funding {market.FundingRate:F4}%");
        }

        // Get account position
        var positions = await _dex.Perps.GetPositionsAsync();
        Console.WriteLine($"\nOpen positions: {positions.Count}");
        foreach (var position in positions)
        {
            Console.WriteLine($"  {position.Symbol}: {position.Side} {position.Size:F4}");
            Console.WriteLine($"    Entry: ${position.EntryPrice:F2}, PnL: ${position.UnrealizedPnl:F2}");
        }

        // Open a long position
        Console.WriteLine("\nOpening long position...");
        var longOrder = await _dex.Perps.PlaceOrderAsync(new PerpOrderRequest
        {
            Symbol = "BTC-USDC-PERP",
            Side = OrderSide.Buy,
            Type = OrderType.Limit,
            Quantity = 0.01m,
            Price = 95000.00m,
            Leverage = 10,
            ReduceOnly = false
        });

        Console.WriteLine($"Position order placed:");
        Console.WriteLine($"  Order ID: {longOrder.OrderId}");
        Console.WriteLine($"  Leverage: {longOrder.Leverage}x");
        Console.WriteLine($"  Margin: ${longOrder.RequiredMargin:F2}");

        // Set stop-loss and take-profit
        Console.WriteLine("\nSetting SL/TP...");
        await _dex.Perps.SetStopLossAsync("BTC-USDC-PERP", 90000.00m);
        await _dex.Perps.SetTakeProfitAsync("BTC-USDC-PERP", 100000.00m);
        Console.WriteLine("  Stop loss: $90,000");
        Console.WriteLine("  Take profit: $100,000");

        // Get funding rate history
        var fundingHistory = await _dex.Perps.GetFundingHistoryAsync("BTC-USDC-PERP", 5);
        Console.WriteLine("\nFunding rate history:");
        foreach (var funding in fundingHistory)
        {
            Console.WriteLine($"  {funding.Timestamp}: {funding.Rate:F4}%");
        }
        Console.WriteLine();
    }

    public async Task RunLiquidityExample()
    {
        Console.WriteLine("=== Liquidity Provision ===");

        // Get available pools
        var pools = await _dex.Liquidity.GetPoolsAsync();
        Console.WriteLine($"Liquidity pools: {pools.Count}");
        foreach (var pool in pools.GetRange(0, Math.Min(pools.Count, 5)))
        {
            Console.WriteLine($"  {pool.Name}: TVL ${pool.TotalValueLocked:N0}, APR {pool.Apr:F2}%");
        }

        // Get pool details
        var ethUsdcPool = await _dex.Liquidity.GetPoolAsync("ETH-USDC");
        Console.WriteLine($"\n{ethUsdcPool.Name} pool:");
        Console.WriteLine($"  TVL: ${ethUsdcPool.TotalValueLocked:N0}");
        Console.WriteLine($"  Volume 24h: ${ethUsdcPool.Volume24h:N0}");
        Console.WriteLine($"  Fee tier: {ethUsdcPool.FeeTier:F2}%");
        Console.WriteLine($"  APR: {ethUsdcPool.Apr:F2}%");
        Console.WriteLine($"  Reserve A: {ethUsdcPool.ReserveA:F4} ETH");
        Console.WriteLine($"  Reserve B: {ethUsdcPool.ReserveB:F2} USDC");

        // Add liquidity
        Console.WriteLine("\nAdding liquidity...");
        var addResult = await _dex.Liquidity.AddLiquidityAsync(new AddLiquidityRequest
        {
            PoolId = "ETH-USDC",
            AmountA = 0.1m,
            AmountB = 300.0m,
            SlippageTolerance = 0.5m
        });

        Console.WriteLine($"Liquidity added:");
        Console.WriteLine($"  LP tokens received: {addResult.LpTokensReceived:F8}");
        Console.WriteLine($"  Share of pool: {addResult.ShareOfPool:F4}%");

        // Get LP positions
        var lpPositions = await _dex.Liquidity.GetPositionsAsync();
        Console.WriteLine($"\nLP positions: {lpPositions.Count}");
        foreach (var position in lpPositions)
        {
            Console.WriteLine($"  {position.PoolId}: {position.LpTokens:F8} tokens, ${position.Value:F2}");
            Console.WriteLine($"    Earned fees: ${position.EarnedFees:F2}");
        }

        // Remove liquidity
        Console.WriteLine("\nRemoving liquidity...");
        var removeResult = await _dex.Liquidity.RemoveLiquidityAsync(new RemoveLiquidityRequest
        {
            PoolId = "ETH-USDC",
            LpTokens = addResult.LpTokensReceived,
            SlippageTolerance = 0.5m
        });

        Console.WriteLine($"Liquidity removed:");
        Console.WriteLine($"  Amount A: {removeResult.AmountA:F4} ETH");
        Console.WriteLine($"  Amount B: {removeResult.AmountB:F2} USDC");
        Console.WriteLine();
    }

    public async Task RunPortfolioExample()
    {
        Console.WriteLine("=== Portfolio Management ===");

        // Get portfolio summary
        var portfolio = await _dex.Portfolio.GetSummaryAsync();
        Console.WriteLine("Portfolio summary:");
        Console.WriteLine($"  Total value: ${portfolio.TotalValue:N2}");
        Console.WriteLine($"  Available: ${portfolio.AvailableBalance:N2}");
        Console.WriteLine($"  In orders: ${portfolio.InOrders:N2}");
        Console.WriteLine($"  In positions: ${portfolio.InPositions:N2}");
        Console.WriteLine($"  Unrealized PnL: ${portfolio.UnrealizedPnl:N2}");

        // Get asset allocation
        Console.WriteLine("\nAsset allocation:");
        foreach (var allocation in portfolio.Allocations)
        {
            Console.WriteLine($"  {allocation.Asset}: {allocation.Percentage:F1}% (${allocation.Value:N2})");
        }

        // Get trade history
        var tradeHistory = await _dex.Portfolio.GetTradeHistoryAsync(new TradeHistoryFilter
        {
            Limit = 10
        });
        Console.WriteLine($"\nRecent trades: {tradeHistory.Count}");
        foreach (var trade in tradeHistory)
        {
            Console.WriteLine($"  {trade.Timestamp}: {trade.Side} {trade.Quantity:F4} {trade.Symbol} @ ${trade.Price:F2}");
        }

        // Get PnL report
        var pnlReport = await _dex.Portfolio.GetPnlReportAsync(Period.Month);
        Console.WriteLine($"\nMonthly PnL report:");
        Console.WriteLine($"  Realized PnL: ${pnlReport.RealizedPnl:N2}");
        Console.WriteLine($"  Unrealized PnL: ${pnlReport.UnrealizedPnl:N2}");
        Console.WriteLine($"  Total fees: ${pnlReport.TotalFees:N2}");
        Console.WriteLine($"  Net profit: ${pnlReport.NetProfit:N2}");
        Console.WriteLine();
    }

    public static async Task Main(string[] args)
    {
        // Initialize client
        var apiKey = Environment.GetEnvironmentVariable("SYNOR_API_KEY") ?? "your-api-key";
        var config = new DexConfig
        {
            ApiKey = apiKey,
            Endpoint = "https://dex.synor.io/v1",
            Timeout = TimeSpan.FromSeconds(30),
            Retries = 3,
            Debug = false
        };

        var dex = new SynorDex(config);
        var example = new DexExample(dex);

        try
        {
            // Check service health
            var healthy = await dex.HealthCheckAsync();
            Console.WriteLine($"Service healthy: {healthy}\n");

            // Run examples
            await example.RunMarketsExample();
            await example.RunSpotTradingExample();
            await example.RunPerpsExample();
            await example.RunLiquidityExample();
            await example.RunPortfolioExample();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error: {ex.Message}");
            Environment.Exit(1);
        }
    }
}
