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

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <synor/dex.hpp>

using namespace synor::dex;

void markets_example(SynorDex& dex) {
    std::cout << "=== Markets ===" << std::endl;

    // Get all markets
    auto markets = dex.markets().list();
    std::cout << "Available markets: " << markets.size() << std::endl;

    for (size_t i = 0; i < std::min(markets.size(), size_t(5)); ++i) {
        const auto& market = markets[i];
        std::cout << "\n  " << market.symbol() << ":" << std::endl;
        std::cout << "    Base: " << market.base_asset() << ", Quote: " << market.quote_asset() << std::endl;
        std::cout << "    Price: " << market.last_price() << std::endl;
        std::cout << "    24h Volume: " << market.volume_24h() << std::endl;
        std::cout << "    24h Change: " << market.change_24h() << "%" << std::endl;
        std::cout << "    Status: " << market.status() << std::endl;
    }

    // Get specific market
    auto market = dex.markets().get("SYN-USDC");
    std::cout << "\nSYN-USDC details:" << std::endl;
    std::cout << "  Min order size: " << market.min_order_size() << std::endl;
    std::cout << "  Tick size: " << market.tick_size() << std::endl;
    std::cout << "  Maker fee: " << market.maker_fee() << "%" << std::endl;
    std::cout << "  Taker fee: " << market.taker_fee() << "%" << std::endl;

    // Get market statistics
    auto stats = dex.markets().get_stats("SYN-USDC");
    std::cout << "\nMarket statistics:" << std::endl;
    std::cout << "  High 24h: " << stats.high_24h() << std::endl;
    std::cout << "  Low 24h: " << stats.low_24h() << std::endl;
    std::cout << "  Open interest: " << stats.open_interest() << std::endl;
    std::cout << "  Funding rate: " << stats.funding_rate() << "%" << std::endl;

    std::cout << std::endl;
}

void spot_trading_example(SynorDex& dex) {
    std::cout << "=== Spot Trading ===" << std::endl;

    // Place a limit order
    std::cout << "Placing limit buy order..." << std::endl;
    auto limit_order = dex.spot().place_order({
        .market = "SYN-USDC",
        .side = OrderSide::Buy,
        .order_type = OrderType::Limit,
        .price = "1.50",
        .quantity = "100",
        .time_in_force = TimeInForce::GTC
    });

    std::cout << "Limit order placed:" << std::endl;
    std::cout << "  Order ID: " << limit_order.order_id() << std::endl;
    std::cout << "  Status: " << limit_order.status() << std::endl;
    std::cout << "  Price: " << limit_order.price() << std::endl;
    std::cout << "  Quantity: " << limit_order.quantity() << std::endl;

    // Place a market order
    std::cout << "\nPlacing market sell order..." << std::endl;
    auto market_order = dex.spot().place_order({
        .market = "SYN-USDC",
        .side = OrderSide::Sell,
        .order_type = OrderType::Market,
        .quantity = "50"
    });

    std::cout << "Market order executed:" << std::endl;
    std::cout << "  Order ID: " << market_order.order_id() << std::endl;
    std::cout << "  Status: " << market_order.status() << std::endl;
    std::cout << "  Filled: " << market_order.filled_quantity() << std::endl;
    std::cout << "  Avg price: " << market_order.average_price() << std::endl;

    // Get order status
    auto status = dex.spot().get_order(limit_order.order_id());
    std::cout << "\nOrder status:" << std::endl;
    std::cout << "  Status: " << status.status() << std::endl;
    std::cout << "  Filled: " << status.filled_quantity() << " / " << status.quantity() << std::endl;
    std::cout << "  Remaining: " << status.remaining_quantity() << std::endl;

    // Cancel order
    std::cout << "\nCancelling order..." << std::endl;
    dex.spot().cancel_order(limit_order.order_id());
    std::cout << "Order cancelled successfully" << std::endl;

    // Get open orders
    auto open_orders = dex.spot().get_open_orders("SYN-USDC");
    std::cout << "\nOpen orders: " << open_orders.size() << std::endl;

    // Get trade history
    auto trades = dex.spot().get_trade_history("SYN-USDC", 10);
    std::cout << "\nRecent trades: " << trades.size() << std::endl;
    for (size_t i = 0; i < std::min(trades.size(), size_t(3)); ++i) {
        const auto& trade = trades[i];
        std::cout << "  " << trade.side() << " " << trade.quantity()
                  << " @ " << trade.price() << " (" << trade.timestamp() << ")" << std::endl;
    }

    std::cout << std::endl;
}

void perps_trading_example(SynorDex& dex) {
    std::cout << "=== Perpetual Futures Trading ===" << std::endl;

    // Get available perps markets
    auto perps_markets = dex.perps().list_markets();
    std::cout << "Available perps markets: " << perps_markets.size() << std::endl;

    for (size_t i = 0; i < std::min(perps_markets.size(), size_t(3)); ++i) {
        const auto& market = perps_markets[i];
        std::cout << "  " << market.symbol() << ": " << market.mark_price()
                  << " (funding: " << market.funding_rate() << "%)" << std::endl;
    }

    // Open a long position
    std::cout << "\nOpening long position..." << std::endl;
    auto position = dex.perps().open_position({
        .market = "SYN-USDC-PERP",
        .side = OrderSide::Buy,
        .order_type = OrderType::Limit,
        .price = "1.50",
        .size = "1000",
        .leverage = 10,
        .reduce_only = false
    });

    std::cout << "Position opened:" << std::endl;
    std::cout << "  Position ID: " << position.position_id() << std::endl;
    std::cout << "  Size: " << position.size() << std::endl;
    std::cout << "  Entry price: " << position.entry_price() << std::endl;
    std::cout << "  Leverage: " << position.leverage() << "x" << std::endl;
    std::cout << "  Liquidation price: " << position.liquidation_price() << std::endl;

    // Get position details
    auto details = dex.perps().get_position(position.position_id());
    std::cout << "\nPosition details:" << std::endl;
    std::cout << "  Unrealized PnL: " << details.unrealized_pnl() << std::endl;
    std::cout << "  Margin: " << details.margin() << std::endl;
    std::cout << "  Margin ratio: " << details.margin_ratio() << "%" << std::endl;

    // Set stop loss and take profit
    std::cout << "\nSetting stop loss and take profit..." << std::endl;
    dex.perps().set_stop_loss(position.position_id(), "1.40");
    std::cout << "Stop loss set at 1.40" << std::endl;

    dex.perps().set_take_profit(position.position_id(), "1.80");
    std::cout << "Take profit set at 1.80" << std::endl;

    // Close position
    std::cout << "\nClosing position..." << std::endl;
    auto close_result = dex.perps().close_position(position.position_id());
    std::cout << "Position closed:" << std::endl;
    std::cout << "  Realized PnL: " << close_result.realized_pnl() << std::endl;
    std::cout << "  Close price: " << close_result.close_price() << std::endl;

    // Get all positions
    auto positions = dex.perps().get_positions();
    std::cout << "\nOpen positions: " << positions.size() << std::endl;

    // Get funding history
    auto funding = dex.perps().get_funding_history("SYN-USDC-PERP", 10);
    std::cout << "Funding payments: " << funding.size() << std::endl;

    std::cout << std::endl;
}

void liquidity_example(SynorDex& dex) {
    std::cout << "=== Liquidity Provision ===" << std::endl;

    // Get available pools
    auto pools = dex.liquidity().list_pools();
    std::cout << "Available pools: " << pools.size() << std::endl;

    for (size_t i = 0; i < std::min(pools.size(), size_t(3)); ++i) {
        const auto& pool = pools[i];
        std::cout << "\n  " << pool.name() << ":" << std::endl;
        std::cout << "    TVL: $" << pool.tvl() << std::endl;
        std::cout << "    APR: " << pool.apr() << "%" << std::endl;
        std::cout << "    Volume 24h: $" << pool.volume_24h() << std::endl;
        std::cout << "    Fee tier: " << pool.fee_tier() << "%" << std::endl;
    }

    // Get pool details
    auto pool = dex.liquidity().get_pool("SYN-USDC");
    std::cout << "\nSYN-USDC pool details:" << std::endl;
    std::cout << "  Token0: " << pool.token0().symbol() << " (" << pool.token0_reserve() << ")" << std::endl;
    std::cout << "  Token1: " << pool.token1().symbol() << " (" << pool.token1_reserve() << ")" << std::endl;
    std::cout << "  Price: " << pool.price() << std::endl;
    std::cout << "  Total LP tokens: " << pool.total_lp_tokens() << std::endl;

    // Add liquidity
    std::cout << "\nAdding liquidity..." << std::endl;
    auto add_result = dex.liquidity().add_liquidity({
        .pool = "SYN-USDC",
        .amount0 = "100",
        .amount1 = "150",
        .slippage_bps = 50  // 0.5%
    });

    std::cout << "Liquidity added:" << std::endl;
    std::cout << "  LP tokens received: " << add_result.lp_tokens() << std::endl;
    std::cout << "  Position ID: " << add_result.position_id() << std::endl;
    std::cout << "  Share of pool: " << add_result.share_of_pool() << "%" << std::endl;

    // Get LP positions
    auto lp_positions = dex.liquidity().get_positions();
    std::cout << "\nLP positions: " << lp_positions.size() << std::endl;
    for (const auto& pos : lp_positions) {
        std::cout << "  " << pos.pool() << ": " << pos.lp_tokens()
                  << " LP tokens (value: $" << pos.value() << ")" << std::endl;
    }

    // Claim fees
    std::cout << "\nClaiming fees..." << std::endl;
    auto fees = dex.liquidity().claim_fees(add_result.position_id());
    std::cout << "Fees claimed:" << std::endl;
    std::cout << "  Token0: " << fees.amount0() << std::endl;
    std::cout << "  Token1: " << fees.amount1() << std::endl;

    // Remove liquidity
    std::cout << "\nRemoving liquidity..." << std::endl;
    auto remove_result = dex.liquidity().remove_liquidity({
        .position_id = add_result.position_id(),
        .lp_tokens = add_result.lp_tokens(),
        .slippage_bps = 50
    });

    std::cout << "Liquidity removed:" << std::endl;
    std::cout << "  Token0 received: " << remove_result.amount0() << std::endl;
    std::cout << "  Token1 received: " << remove_result.amount1() << std::endl;

    std::cout << std::endl;
}

void orderbook_example(SynorDex& dex) {
    std::cout << "=== Order Book ===" << std::endl;

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

    std::cout << "Order book for SYN-USDC:" << std::endl;
    std::cout << "\nAsks (sells):" << std::endl;
    for (size_t i = 0; i < std::min(orderbook.asks().size(), size_t(5)); ++i) {
        const auto& ask = orderbook.asks()[i];
        std::cout << "  " << ask.quantity() << " @ " << ask.price() << std::endl;
    }

    std::cout << "\nBids (buys):" << std::endl;
    for (size_t i = 0; i < std::min(orderbook.bids().size(), size_t(5)); ++i) {
        const auto& bid = orderbook.bids()[i];
        std::cout << "  " << bid.quantity() << " @ " << bid.price() << std::endl;
    }

    std::cout << "\nSpread: " << orderbook.spread() << " (" << orderbook.spread_percent() << "%)" << std::endl;
    std::cout << "Mid price: " << orderbook.mid_price() << std::endl;

    // Get recent trades
    auto recent_trades = dex.orderbook().get_recent_trades("SYN-USDC", 10);
    std::cout << "\nRecent trades:" << std::endl;
    for (size_t i = 0; i < std::min(recent_trades.size(), size_t(5)); ++i) {
        const auto& trade = recent_trades[i];
        std::cout << "  " << trade.side() << " " << trade.quantity() << " @ " << trade.price() << std::endl;
    }

    std::cout << std::endl;
}

void portfolio_example(SynorDex& dex) {
    std::cout << "=== Portfolio ===" << std::endl;

    // Get portfolio overview
    auto portfolio = dex.portfolio().get_overview();

    std::cout << "Portfolio overview:" << std::endl;
    std::cout << "  Total value: $" << portfolio.total_value() << std::endl;
    std::cout << "  Available balance: $" << portfolio.available_balance() << std::endl;
    std::cout << "  In orders: $" << portfolio.in_orders() << std::endl;
    std::cout << "  In positions: $" << portfolio.in_positions() << std::endl;
    std::cout << "  Unrealized PnL: $" << portfolio.unrealized_pnl() << std::endl;

    // Get balances
    auto balances = dex.portfolio().get_balances();
    std::cout << "\nBalances:" << std::endl;
    for (const auto& balance : balances) {
        std::cout << "  " << balance.asset() << ": " << balance.total()
                  << " (available: " << balance.available()
                  << ", in orders: " << balance.in_orders() << ")" << std::endl;
    }

    // Get PnL history
    auto pnl_history = dex.portfolio().get_pnl_history(30);
    std::cout << "\nPnL history (last " << pnl_history.size() << " days):" << std::endl;
    if (!pnl_history.empty()) {
        std::cout << "  Total PnL: $" << pnl_history.back().cumulative_pnl() << std::endl;
    }

    // Get trade statistics
    auto stats = dex.portfolio().get_stats();
    std::cout << "\nTrade statistics:" << std::endl;
    std::cout << "  Total trades: " << stats.total_trades() << std::endl;
    std::cout << "  Win rate: " << stats.win_rate() << "%" << std::endl;
    std::cout << "  Avg profit: $" << stats.avg_profit() << std::endl;
    std::cout << "  Avg loss: $" << stats.avg_loss() << std::endl;
    std::cout << "  Best trade: $" << stats.best_trade() << std::endl;
    std::cout << "  Worst trade: $" << stats.worst_trade() << std::endl;

    std::cout << std::endl;
}

int main(int argc, char** argv) {
    // Initialize client
    const char* api_key = std::getenv("SYNOR_API_KEY");
    DexConfig config{
        .api_key = api_key ? api_key : "your-api-key",
        .endpoint = "https://dex.synor.io/v1",
        .timeout = std::chrono::seconds(30),
        .retries = 3,
        .debug = false,
        .default_market = "SYN-USDC"
    };

    SynorDex dex(config);

    try {
        // Check service health
        bool healthy = dex.health_check();
        std::cout << "Service healthy: " << (healthy ? "true" : "false") << std::endl << std::endl;

        // Run examples
        markets_example(dex);
        spot_trading_example(dex);
        perps_trading_example(dex);
        liquidity_example(dex);
        orderbook_example(dex);
        portfolio_example(dex);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}
