/**
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <synor/dex.h>

void markets_example(synor_dex_t* dex) {
    printf("=== Markets ===\n");

    synor_error_t err;
    synor_market_list_t* markets = NULL;

    // Get all markets
    err = synor_markets_list(dex, &markets);
    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to get markets\n");
        return;
    }

    printf("Available markets: %zu\n", synor_market_list_count(markets));

    for (size_t i = 0; i < 5 && i < synor_market_list_count(markets); i++) {
        synor_market_t* market = synor_market_list_get(markets, i);
        printf("\n  %s:\n", synor_market_get_symbol(market));
        printf("    Base: %s, Quote: %s\n",
               synor_market_get_base_asset(market),
               synor_market_get_quote_asset(market));
        printf("    Price: %s\n", synor_market_get_last_price(market));
        printf("    24h Volume: %s\n", synor_market_get_volume_24h(market));
        printf("    24h Change: %s%%\n", synor_market_get_change_24h(market));
        printf("    Status: %s\n", synor_market_get_status(market));
    }

    // Get specific market
    synor_market_t* market = NULL;
    err = synor_markets_get(dex, "SYN-USDC", &market);
    if (err == SYNOR_OK) {
        printf("\nSYN-USDC details:\n");
        printf("  Min order size: %s\n", synor_market_get_min_order_size(market));
        printf("  Tick size: %s\n", synor_market_get_tick_size(market));
        printf("  Maker fee: %s%%\n", synor_market_get_maker_fee(market));
        printf("  Taker fee: %s%%\n", synor_market_get_taker_fee(market));
        synor_market_free(market);
    }

    // Get market statistics
    synor_market_stats_t* stats = NULL;
    err = synor_markets_get_stats(dex, "SYN-USDC", &stats);
    if (err == SYNOR_OK) {
        printf("\nMarket statistics:\n");
        printf("  High 24h: %s\n", synor_stats_get_high_24h(stats));
        printf("  Low 24h: %s\n", synor_stats_get_low_24h(stats));
        printf("  Open interest: %s\n", synor_stats_get_open_interest(stats));
        printf("  Funding rate: %s%%\n", synor_stats_get_funding_rate(stats));
        synor_market_stats_free(stats);
    }

    synor_market_list_free(markets);
    printf("\n");
}

void spot_trading_example(synor_dex_t* dex) {
    printf("=== Spot Trading ===\n");

    synor_error_t err;

    // Place a limit order
    printf("Placing limit buy order...\n");
    synor_order_request_t limit_req = {
        .market = "SYN-USDC",
        .side = SYNOR_ORDER_SIDE_BUY,
        .order_type = SYNOR_ORDER_TYPE_LIMIT,
        .price = "1.50",
        .quantity = "100",
        .time_in_force = SYNOR_TIME_IN_FORCE_GTC
    };

    synor_order_result_t* limit_order = NULL;
    err = synor_spot_place_order(dex, &limit_req, &limit_order);
    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to place limit order\n");
        return;
    }

    printf("Limit order placed:\n");
    printf("  Order ID: %s\n", synor_order_get_id(limit_order));
    printf("  Status: %s\n", synor_order_get_status(limit_order));
    printf("  Price: %s\n", synor_order_get_price(limit_order));
    printf("  Quantity: %s\n", synor_order_get_quantity(limit_order));

    // Place a market order
    printf("\nPlacing market sell order...\n");
    synor_order_request_t market_req = {
        .market = "SYN-USDC",
        .side = SYNOR_ORDER_SIDE_SELL,
        .order_type = SYNOR_ORDER_TYPE_MARKET,
        .quantity = "50"
    };

    synor_order_result_t* market_order = NULL;
    err = synor_spot_place_order(dex, &market_req, &market_order);
    if (err == SYNOR_OK) {
        printf("Market order executed:\n");
        printf("  Order ID: %s\n", synor_order_get_id(market_order));
        printf("  Status: %s\n", synor_order_get_status(market_order));
        printf("  Filled: %s\n", synor_order_get_filled_quantity(market_order));
        printf("  Avg price: %s\n", synor_order_get_avg_price(market_order));
        synor_order_result_free(market_order);
    }

    // Get order status
    synor_order_status_t* status = NULL;
    err = synor_spot_get_order(dex, synor_order_get_id(limit_order), &status);
    if (err == SYNOR_OK) {
        printf("\nOrder status:\n");
        printf("  Status: %s\n", synor_order_status_get_status(status));
        printf("  Filled: %s / %s\n",
               synor_order_status_get_filled(status),
               synor_order_status_get_quantity(status));
        printf("  Remaining: %s\n", synor_order_status_get_remaining(status));
        synor_order_status_free(status);
    }

    // Cancel order
    printf("\nCancelling order...\n");
    err = synor_spot_cancel_order(dex, synor_order_get_id(limit_order));
    if (err == SYNOR_OK) {
        printf("Order cancelled successfully\n");
    }

    // Get open orders
    synor_order_list_t* open_orders = NULL;
    err = synor_spot_get_open_orders(dex, "SYN-USDC", &open_orders);
    if (err == SYNOR_OK) {
        printf("\nOpen orders: %zu\n", synor_order_list_count(open_orders));
        synor_order_list_free(open_orders);
    }

    // Get trade history
    synor_trade_list_t* trades = NULL;
    err = synor_spot_get_trade_history(dex, "SYN-USDC", 10, &trades);
    if (err == SYNOR_OK) {
        printf("\nRecent trades: %zu\n", synor_trade_list_count(trades));
        for (size_t i = 0; i < 3 && i < synor_trade_list_count(trades); i++) {
            synor_trade_t* trade = synor_trade_list_get(trades, i);
            printf("  %s %s @ %s (%s)\n",
                   synor_trade_get_side(trade),
                   synor_trade_get_quantity(trade),
                   synor_trade_get_price(trade),
                   synor_trade_get_timestamp(trade));
        }
        synor_trade_list_free(trades);
    }

    synor_order_result_free(limit_order);
    printf("\n");
}

void perps_trading_example(synor_dex_t* dex) {
    printf("=== Perpetual Futures Trading ===\n");

    synor_error_t err;

    // Get available perps markets
    synor_perps_market_list_t* perps_markets = NULL;
    err = synor_perps_list_markets(dex, &perps_markets);
    if (err == SYNOR_OK) {
        printf("Available perps markets: %zu\n", synor_perps_market_list_count(perps_markets));
        for (size_t i = 0; i < 3 && i < synor_perps_market_list_count(perps_markets); i++) {
            synor_perps_market_t* market = synor_perps_market_list_get(perps_markets, i);
            printf("  %s: %s (funding: %s%%)\n",
                   synor_perps_market_get_symbol(market),
                   synor_perps_market_get_mark_price(market),
                   synor_perps_market_get_funding_rate(market));
        }
        synor_perps_market_list_free(perps_markets);
    }

    // Open a long position
    printf("\nOpening long position...\n");
    synor_perps_order_request_t perps_req = {
        .market = "SYN-USDC-PERP",
        .side = SYNOR_ORDER_SIDE_BUY,
        .order_type = SYNOR_ORDER_TYPE_LIMIT,
        .price = "1.50",
        .size = "1000",
        .leverage = 10,
        .reduce_only = false
    };

    synor_position_t* position = NULL;
    err = synor_perps_open_position(dex, &perps_req, &position);
    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to open position\n");
        return;
    }

    printf("Position opened:\n");
    printf("  Position ID: %s\n", synor_position_get_id(position));
    printf("  Size: %s\n", synor_position_get_size(position));
    printf("  Entry price: %s\n", synor_position_get_entry_price(position));
    printf("  Leverage: %dx\n", synor_position_get_leverage(position));
    printf("  Liquidation price: %s\n", synor_position_get_liquidation_price(position));

    // Get position details
    synor_position_details_t* details = NULL;
    err = synor_perps_get_position(dex, synor_position_get_id(position), &details);
    if (err == SYNOR_OK) {
        printf("\nPosition details:\n");
        printf("  Unrealized PnL: %s\n", synor_position_details_get_unrealized_pnl(details));
        printf("  Margin: %s\n", synor_position_details_get_margin(details));
        printf("  Margin ratio: %s%%\n", synor_position_details_get_margin_ratio(details));
        synor_position_details_free(details);
    }

    // Set stop loss and take profit
    printf("\nSetting stop loss and take profit...\n");
    err = synor_perps_set_stop_loss(dex, synor_position_get_id(position), "1.40");
    if (err == SYNOR_OK) printf("Stop loss set at 1.40\n");

    err = synor_perps_set_take_profit(dex, synor_position_get_id(position), "1.80");
    if (err == SYNOR_OK) printf("Take profit set at 1.80\n");

    // Close position
    printf("\nClosing position...\n");
    synor_close_result_t* close_result = NULL;
    err = synor_perps_close_position(dex, synor_position_get_id(position), &close_result);
    if (err == SYNOR_OK) {
        printf("Position closed:\n");
        printf("  Realized PnL: %s\n", synor_close_result_get_realized_pnl(close_result));
        printf("  Close price: %s\n", synor_close_result_get_close_price(close_result));
        synor_close_result_free(close_result);
    }

    // Get all positions
    synor_position_list_t* positions = NULL;
    err = synor_perps_get_positions(dex, &positions);
    if (err == SYNOR_OK) {
        printf("\nOpen positions: %zu\n", synor_position_list_count(positions));
        synor_position_list_free(positions);
    }

    synor_position_free(position);
    printf("\n");
}

void liquidity_example(synor_dex_t* dex) {
    printf("=== Liquidity Provision ===\n");

    synor_error_t err;

    // Get available pools
    synor_pool_list_t* pools = NULL;
    err = synor_liquidity_list_pools(dex, &pools);
    if (err == SYNOR_OK) {
        printf("Available pools: %zu\n", synor_pool_list_count(pools));
        for (size_t i = 0; i < 3 && i < synor_pool_list_count(pools); i++) {
            synor_pool_t* pool = synor_pool_list_get(pools, i);
            printf("\n  %s:\n", synor_pool_get_name(pool));
            printf("    TVL: $%s\n", synor_pool_get_tvl(pool));
            printf("    APR: %s%%\n", synor_pool_get_apr(pool));
            printf("    Volume 24h: $%s\n", synor_pool_get_volume_24h(pool));
            printf("    Fee tier: %s%%\n", synor_pool_get_fee_tier(pool));
        }
        synor_pool_list_free(pools);
    }

    // Get pool details
    synor_pool_details_t* pool = NULL;
    err = synor_liquidity_get_pool(dex, "SYN-USDC", &pool);
    if (err == SYNOR_OK) {
        printf("\nSYN-USDC pool details:\n");
        printf("  Token0: %s (%s)\n",
               synor_pool_details_get_token0_symbol(pool),
               synor_pool_details_get_token0_reserve(pool));
        printf("  Token1: %s (%s)\n",
               synor_pool_details_get_token1_symbol(pool),
               synor_pool_details_get_token1_reserve(pool));
        printf("  Price: %s\n", synor_pool_details_get_price(pool));
        printf("  Total LP tokens: %s\n", synor_pool_details_get_total_lp_tokens(pool));
        synor_pool_details_free(pool);
    }

    // Add liquidity
    printf("\nAdding liquidity...\n");
    synor_add_liquidity_request_t add_req = {
        .pool = "SYN-USDC",
        .amount0 = "100",
        .amount1 = "150",
        .slippage_bps = 50  // 0.5%
    };

    synor_add_liquidity_result_t* add_result = NULL;
    err = synor_liquidity_add(dex, &add_req, &add_result);
    if (err == SYNOR_OK) {
        printf("Liquidity added:\n");
        printf("  LP tokens received: %s\n", synor_add_result_get_lp_tokens(add_result));
        printf("  Position ID: %s\n", synor_add_result_get_position_id(add_result));
        printf("  Share of pool: %s%%\n", synor_add_result_get_share_of_pool(add_result));

        // Claim fees
        printf("\nClaiming fees...\n");
        synor_claim_fees_result_t* fees = NULL;
        err = synor_liquidity_claim_fees(dex, synor_add_result_get_position_id(add_result), &fees);
        if (err == SYNOR_OK) {
            printf("Fees claimed:\n");
            printf("  Token0: %s\n", synor_claim_fees_get_amount0(fees));
            printf("  Token1: %s\n", synor_claim_fees_get_amount1(fees));
            synor_claim_fees_result_free(fees);
        }

        // Remove liquidity
        printf("\nRemoving liquidity...\n");
        synor_remove_liquidity_request_t remove_req = {
            .position_id = synor_add_result_get_position_id(add_result),
            .lp_tokens = synor_add_result_get_lp_tokens(add_result),
            .slippage_bps = 50
        };

        synor_remove_liquidity_result_t* remove_result = NULL;
        err = synor_liquidity_remove(dex, &remove_req, &remove_result);
        if (err == SYNOR_OK) {
            printf("Liquidity removed:\n");
            printf("  Token0 received: %s\n", synor_remove_result_get_amount0(remove_result));
            printf("  Token1 received: %s\n", synor_remove_result_get_amount1(remove_result));
            synor_remove_liquidity_result_free(remove_result);
        }

        synor_add_liquidity_result_free(add_result);
    }

    printf("\n");
}

void orderbook_example(synor_dex_t* dex) {
    printf("=== Order Book ===\n");

    synor_error_t err;

    // Get order book snapshot
    synor_orderbook_t* orderbook = NULL;
    err = synor_orderbook_get_snapshot(dex, "SYN-USDC", 10, &orderbook);
    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to get orderbook\n");
        return;
    }

    printf("Order book for SYN-USDC:\n");

    printf("\nAsks (sells):\n");
    for (size_t i = 0; i < 5 && i < synor_orderbook_get_ask_count(orderbook); i++) {
        synor_orderbook_entry_t* ask = synor_orderbook_get_ask(orderbook, i);
        printf("  %s @ %s\n",
               synor_orderbook_entry_get_quantity(ask),
               synor_orderbook_entry_get_price(ask));
    }

    printf("\nBids (buys):\n");
    for (size_t i = 0; i < 5 && i < synor_orderbook_get_bid_count(orderbook); i++) {
        synor_orderbook_entry_t* bid = synor_orderbook_get_bid(orderbook, i);
        printf("  %s @ %s\n",
               synor_orderbook_entry_get_quantity(bid),
               synor_orderbook_entry_get_price(bid));
    }

    printf("\nSpread: %s (%s%%)\n",
           synor_orderbook_get_spread(orderbook),
           synor_orderbook_get_spread_percent(orderbook));
    printf("Mid price: %s\n", synor_orderbook_get_mid_price(orderbook));

    synor_orderbook_free(orderbook);

    // Get recent trades
    synor_trade_list_t* recent_trades = NULL;
    err = synor_orderbook_get_recent_trades(dex, "SYN-USDC", 10, &recent_trades);
    if (err == SYNOR_OK) {
        printf("\nRecent trades:\n");
        for (size_t i = 0; i < 5 && i < synor_trade_list_count(recent_trades); i++) {
            synor_trade_t* trade = synor_trade_list_get(recent_trades, i);
            printf("  %s %s @ %s\n",
                   synor_trade_get_side(trade),
                   synor_trade_get_quantity(trade),
                   synor_trade_get_price(trade));
        }
        synor_trade_list_free(recent_trades);
    }

    printf("\n");
}

void portfolio_example(synor_dex_t* dex) {
    printf("=== Portfolio ===\n");

    synor_error_t err;

    // Get portfolio overview
    synor_portfolio_t* portfolio = NULL;
    err = synor_portfolio_get_overview(dex, &portfolio);
    if (err == SYNOR_OK) {
        printf("Portfolio overview:\n");
        printf("  Total value: $%s\n", synor_portfolio_get_total_value(portfolio));
        printf("  Available balance: $%s\n", synor_portfolio_get_available_balance(portfolio));
        printf("  In orders: $%s\n", synor_portfolio_get_in_orders(portfolio));
        printf("  In positions: $%s\n", synor_portfolio_get_in_positions(portfolio));
        printf("  Unrealized PnL: $%s\n", synor_portfolio_get_unrealized_pnl(portfolio));
        synor_portfolio_free(portfolio);
    }

    // Get balances
    synor_balance_list_t* balances = NULL;
    err = synor_portfolio_get_balances(dex, &balances);
    if (err == SYNOR_OK) {
        printf("\nBalances:\n");
        for (size_t i = 0; i < synor_balance_list_count(balances); i++) {
            synor_balance_t* balance = synor_balance_list_get(balances, i);
            printf("  %s: %s (available: %s, in orders: %s)\n",
                   synor_balance_get_asset(balance),
                   synor_balance_get_total(balance),
                   synor_balance_get_available(balance),
                   synor_balance_get_in_orders(balance));
        }
        synor_balance_list_free(balances);
    }

    // Get trade statistics
    synor_trade_stats_t* stats = NULL;
    err = synor_portfolio_get_stats(dex, &stats);
    if (err == SYNOR_OK) {
        printf("\nTrade statistics:\n");
        printf("  Total trades: %d\n", synor_trade_stats_get_total_trades(stats));
        printf("  Win rate: %s%%\n", synor_trade_stats_get_win_rate(stats));
        printf("  Avg profit: $%s\n", synor_trade_stats_get_avg_profit(stats));
        printf("  Avg loss: $%s\n", synor_trade_stats_get_avg_loss(stats));
        printf("  Best trade: $%s\n", synor_trade_stats_get_best_trade(stats));
        printf("  Worst trade: $%s\n", synor_trade_stats_get_worst_trade(stats));
        synor_trade_stats_free(stats);
    }

    printf("\n");
}

int main(int argc, char** argv) {
    synor_error_t err;

    // Initialize client
    synor_dex_config_t config = {
        .api_key = getenv("SYNOR_API_KEY") ? getenv("SYNOR_API_KEY") : "your-api-key",
        .endpoint = "https://dex.synor.io/v1",
        .timeout_ms = 30000,
        .retries = 3,
        .debug = false,
        .default_market = "SYN-USDC"
    };

    synor_dex_t* dex = NULL;
    err = synor_dex_init(&config, &dex);
    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to initialize DEX client: %s\n", synor_error_string(err));
        return 1;
    }

    // Check service health
    bool healthy;
    err = synor_dex_health_check(dex, &healthy);
    printf("Service healthy: %s\n\n", healthy ? "true" : "false");

    // Run examples
    markets_example(dex);
    spot_trading_example(dex);
    perps_trading_example(dex);
    liquidity_example(dex);
    orderbook_example(dex);
    portfolio_example(dex);

    // Cleanup
    synor_dex_free(dex);

    return 0;
}
