import Foundation
import SynorDex

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

@main
struct DexExample {
    static func main() async throws {
        // Initialize client
        let config = DexConfig(
            apiKey: ProcessInfo.processInfo.environment["SYNOR_API_KEY"] ?? "your-api-key",
            endpoint: "https://dex.synor.io/v1",
            timeout: 30,
            retries: 3,
            debug: false,
            defaultMarket: "SYN-USDC"
        )

        let dex = SynorDex(config: config)

        do {
            // Check service health
            let healthy = try await dex.healthCheck()
            print("Service healthy: \(healthy)\n")

            // Run examples
            try await marketsExample(dex: dex)
            try await spotTradingExample(dex: dex)
            try await perpsTradingExample(dex: dex)
            try await liquidityExample(dex: dex)
            try await orderbookExample(dex: dex)
            try await portfolioExample(dex: dex)
        } catch {
            print("Error: \(error)")
        }

        await dex.close()
    }

    static func marketsExample(dex: SynorDex) async throws {
        print("=== Markets ===")

        // Get all markets
        let markets = try await dex.markets.list()
        print("Available markets: \(markets.count)")

        for market in markets.prefix(5) {
            print("\n  \(market.symbol):")
            print("    Base: \(market.baseAsset), Quote: \(market.quoteAsset)")
            print("    Price: \(market.lastPrice)")
            print("    24h Volume: \(market.volume24h)")
            print("    24h Change: \(market.change24h)%")
            print("    Status: \(market.status)")
        }

        // Get specific market
        let market = try await dex.markets.get(symbol: "SYN-USDC")
        print("\nSYN-USDC details:")
        print("  Min order size: \(market.minOrderSize)")
        print("  Tick size: \(market.tickSize)")
        print("  Maker fee: \(market.makerFee)%")
        print("  Taker fee: \(market.takerFee)%")

        // Get market statistics
        let stats = try await dex.markets.getStats(symbol: "SYN-USDC")
        print("\nMarket statistics:")
        print("  High 24h: \(stats.high24h)")
        print("  Low 24h: \(stats.low24h)")
        print("  Open interest: \(stats.openInterest)")
        print("  Funding rate: \(stats.fundingRate)%")

        print()
    }

    static func spotTradingExample(dex: SynorDex) async throws {
        print("=== Spot Trading ===")

        // Place a limit order
        print("Placing limit buy order...")
        let limitOrder = try await dex.spot.placeOrder(
            OrderRequest(
                market: "SYN-USDC",
                side: .buy,
                orderType: .limit,
                price: "1.50",
                quantity: "100",
                timeInForce: .gtc
            )
        )

        print("Limit order placed:")
        print("  Order ID: \(limitOrder.orderId)")
        print("  Status: \(limitOrder.status)")
        print("  Price: \(limitOrder.price)")
        print("  Quantity: \(limitOrder.quantity)")

        // Place a market order
        print("\nPlacing market sell order...")
        let marketOrder = try await dex.spot.placeOrder(
            OrderRequest(
                market: "SYN-USDC",
                side: .sell,
                orderType: .market,
                quantity: "50"
            )
        )

        print("Market order executed:")
        print("  Order ID: \(marketOrder.orderId)")
        print("  Status: \(marketOrder.status)")
        print("  Filled: \(marketOrder.filledQuantity)")
        print("  Avg price: \(marketOrder.averagePrice)")

        // Get order status
        let status = try await dex.spot.getOrder(orderId: limitOrder.orderId)
        print("\nOrder status:")
        print("  Status: \(status.status)")
        print("  Filled: \(status.filledQuantity) / \(status.quantity)")
        print("  Remaining: \(status.remainingQuantity)")

        // Cancel order
        print("\nCancelling order...")
        try await dex.spot.cancelOrder(orderId: limitOrder.orderId)
        print("Order cancelled successfully")

        // Get open orders
        let openOrders = try await dex.spot.getOpenOrders(market: "SYN-USDC")
        print("\nOpen orders: \(openOrders.count)")

        // Get trade history
        let trades = try await dex.spot.getTradeHistory(market: "SYN-USDC", limit: 10)
        print("\nRecent trades: \(trades.count)")
        for trade in trades.prefix(3) {
            print("  \(trade.side) \(trade.quantity) @ \(trade.price) (\(trade.timestamp))")
        }

        print()
    }

    static func perpsTradingExample(dex: SynorDex) async throws {
        print("=== Perpetual Futures Trading ===")

        // Get available perps markets
        let perpsMarkets = try await dex.perps.listMarkets()
        print("Available perps markets: \(perpsMarkets.count)")

        for market in perpsMarkets.prefix(3) {
            print("  \(market.symbol): \(market.markPrice) (funding: \(market.fundingRate)%)")
        }

        // Open a long position
        print("\nOpening long position...")
        let position = try await dex.perps.openPosition(
            PerpsOrderRequest(
                market: "SYN-USDC-PERP",
                side: .buy,
                orderType: .limit,
                price: "1.50",
                size: "1000",
                leverage: 10,
                reduceOnly: false
            )
        )

        print("Position opened:")
        print("  Position ID: \(position.positionId)")
        print("  Size: \(position.size)")
        print("  Entry price: \(position.entryPrice)")
        print("  Leverage: \(position.leverage)x")
        print("  Liquidation price: \(position.liquidationPrice)")

        // Get position details
        let details = try await dex.perps.getPosition(positionId: position.positionId)
        print("\nPosition details:")
        print("  Unrealized PnL: \(details.unrealizedPnL)")
        print("  Margin: \(details.margin)")
        print("  Margin ratio: \(details.marginRatio)%")

        // Set stop loss and take profit
        print("\nSetting stop loss and take profit...")
        try await dex.perps.setStopLoss(positionId: position.positionId, price: "1.40")
        print("Stop loss set at 1.40")

        try await dex.perps.setTakeProfit(positionId: position.positionId, price: "1.80")
        print("Take profit set at 1.80")

        // Close position
        print("\nClosing position...")
        let closeResult = try await dex.perps.closePosition(positionId: position.positionId)
        print("Position closed:")
        print("  Realized PnL: \(closeResult.realizedPnL)")
        print("  Close price: \(closeResult.closePrice)")

        // Get all positions
        let positions = try await dex.perps.getPositions()
        print("\nOpen positions: \(positions.count)")

        // Get funding history
        let funding = try await dex.perps.getFundingHistory(market: "SYN-USDC-PERP", limit: 10)
        print("Funding payments: \(funding.count)")

        print()
    }

    static func liquidityExample(dex: SynorDex) async throws {
        print("=== Liquidity Provision ===")

        // Get available pools
        let pools = try await dex.liquidity.listPools()
        print("Available pools: \(pools.count)")

        for pool in pools.prefix(3) {
            print("\n  \(pool.name):")
            print("    TVL: $\(pool.tvl)")
            print("    APR: \(pool.apr)%")
            print("    Volume 24h: $\(pool.volume24h)")
            print("    Fee tier: \(pool.feeTier)%")
        }

        // Get pool details
        let pool = try await dex.liquidity.getPool(poolId: "SYN-USDC")
        print("\nSYN-USDC pool details:")
        print("  Token0: \(pool.token0.symbol) (\(pool.token0Reserve))")
        print("  Token1: \(pool.token1.symbol) (\(pool.token1Reserve))")
        print("  Price: \(pool.price)")
        print("  Total LP tokens: \(pool.totalLPTokens)")

        // Add liquidity
        print("\nAdding liquidity...")
        let addResult = try await dex.liquidity.addLiquidity(
            AddLiquidityRequest(
                pool: "SYN-USDC",
                amount0: "100",
                amount1: "150",
                slippageBps: 50 // 0.5%
            )
        )

        print("Liquidity added:")
        print("  LP tokens received: \(addResult.lpTokens)")
        print("  Position ID: \(addResult.positionId)")
        print("  Share of pool: \(addResult.shareOfPool)%")

        // Get LP positions
        let lpPositions = try await dex.liquidity.getPositions()
        print("\nLP positions: \(lpPositions.count)")
        for pos in lpPositions {
            print("  \(pos.pool): \(pos.lpTokens) LP tokens (value: $\(pos.value))")
        }

        // Claim fees
        print("\nClaiming fees...")
        let fees = try await dex.liquidity.claimFees(positionId: addResult.positionId)
        print("Fees claimed:")
        print("  Token0: \(fees.amount0)")
        print("  Token1: \(fees.amount1)")

        // Remove liquidity
        print("\nRemoving liquidity...")
        let removeResult = try await dex.liquidity.removeLiquidity(
            RemoveLiquidityRequest(
                positionId: addResult.positionId,
                lpTokens: addResult.lpTokens,
                slippageBps: 50
            )
        )

        print("Liquidity removed:")
        print("  Token0 received: \(removeResult.amount0)")
        print("  Token1 received: \(removeResult.amount1)")

        print()
    }

    static func orderbookExample(dex: SynorDex) async throws {
        print("=== Order Book ===")

        // Get order book snapshot
        let orderbook = try await dex.orderbook.getSnapshot(market: "SYN-USDC", depth: 10)

        print("Order book for SYN-USDC:")
        print("\nAsks (sells):")
        for ask in orderbook.asks.prefix(5) {
            print("  \(ask.quantity) @ \(ask.price)")
        }

        print("\nBids (buys):")
        for bid in orderbook.bids.prefix(5) {
            print("  \(bid.quantity) @ \(bid.price)")
        }

        print("\nSpread: \(orderbook.spread) (\(orderbook.spreadPercent)%)")
        print("Mid price: \(orderbook.midPrice)")

        // Get recent trades
        let recentTrades = try await dex.orderbook.getRecentTrades(market: "SYN-USDC", limit: 10)
        print("\nRecent trades:")
        for trade in recentTrades.prefix(5) {
            print("  \(trade.side) \(trade.quantity) @ \(trade.price)")
        }

        print()
    }

    static func portfolioExample(dex: SynorDex) async throws {
        print("=== Portfolio ===")

        // Get portfolio overview
        let portfolio = try await dex.portfolio.getOverview()

        print("Portfolio overview:")
        print("  Total value: $\(portfolio.totalValue)")
        print("  Available balance: $\(portfolio.availableBalance)")
        print("  In orders: $\(portfolio.inOrders)")
        print("  In positions: $\(portfolio.inPositions)")
        print("  Unrealized PnL: $\(portfolio.unrealizedPnL)")

        // Get balances
        let balances = try await dex.portfolio.getBalances()
        print("\nBalances:")
        for balance in balances {
            print("  \(balance.asset): \(balance.total) (available: \(balance.available), in orders: \(balance.inOrders))")
        }

        // Get PnL history
        let pnlHistory = try await dex.portfolio.getPnLHistory(days: 30)
        print("\nPnL history (last \(pnlHistory.count) days):")
        if let last = pnlHistory.last {
            print("  Total PnL: $\(last.cumulativePnL)")
        }

        // Get trade statistics
        let stats = try await dex.portfolio.getStats()
        print("\nTrade statistics:")
        print("  Total trades: \(stats.totalTrades)")
        print("  Win rate: \(stats.winRate)%")
        print("  Avg profit: $\(stats.avgProfit)")
        print("  Avg loss: $\(stats.avgLoss)")
        print("  Best trade: $\(stats.bestTrade)")
        print("  Worst trade: $\(stats.worstTrade)")

        print()
    }
}
