import Foundation

public enum PoolType: String, Codable {
    case constantProduct = "constant_product"
    case stable = "stable"
    case concentrated = "concentrated"
}

public enum PositionSide: String, Codable {
    case long = "long"
    case short = "short"
}

public enum OrderType: String, Codable {
    case market = "market"
    case limit = "limit"
    case stopMarket = "stop_market"
    case stopLimit = "stop_limit"
    case takeProfit = "take_profit"
    case takeProfitLimit = "take_profit_limit"
}

public enum MarginType: String, Codable {
    case cross = "cross"
    case isolated = "isolated"
}

public enum TimeInForce: String, Codable {
    case GTC, IOC, FOK, GTD
}

public enum OrderStatus: String, Codable {
    case pending = "pending"
    case open = "open"
    case partiallyFilled = "partially_filled"
    case filled = "filled"
    case cancelled = "cancelled"
    case expired = "expired"
}

public struct Token: Codable {
    public let address: String
    public let symbol: String
    public let name: String
    public let decimals: Int
    public let totalSupply: String
    public let priceUsd: Double?
    public let logoUrl: String?
    public let verified: Bool

    enum CodingKeys: String, CodingKey {
        case address, symbol, name, decimals, verified
        case totalSupply = "total_supply"
        case priceUsd = "price_usd"
        case logoUrl = "logo_url"
    }
}

public struct Pool: Codable {
    public let id: String
    public let tokenA: Token
    public let tokenB: Token
    public let poolType: PoolType
    public let reserveA: String
    public let reserveB: String
    public let fee: Double
    public let tvlUsd: Double
    public let volume24h: Double
    public let apr: Double
    public let lpTokenAddress: String
    public let tickSpacing: Int?
    public let sqrtPrice: String?

    enum CodingKeys: String, CodingKey {
        case id, fee, apr
        case tokenA = "token_a"
        case tokenB = "token_b"
        case poolType = "pool_type"
        case reserveA = "reserve_a"
        case reserveB = "reserve_b"
        case tvlUsd = "tvl_usd"
        case volume24h = "volume_24h"
        case lpTokenAddress = "lp_token_address"
        case tickSpacing = "tick_spacing"
        case sqrtPrice = "sqrt_price"
    }
}

public struct PoolFilter {
    public var tokens: [String]?
    public var minTvl: Double?
    public var minVolume24h: Double?
    public var verified: Bool?
    public var limit: Int?
    public var offset: Int?

    public init() {}
}

public struct Quote: Codable {
    public let tokenIn: String
    public let tokenOut: String
    public let amountIn: String
    public let amountOut: String
    public let priceImpact: Double
    public let route: [String]
    public let fee: String
    public let minimumReceived: String
    public let expiresAt: Int

    enum CodingKeys: String, CodingKey {
        case route, fee
        case tokenIn = "token_in"
        case tokenOut = "token_out"
        case amountIn = "amount_in"
        case amountOut = "amount_out"
        case priceImpact = "price_impact"
        case minimumReceived = "minimum_received"
        case expiresAt = "expires_at"
    }
}

public struct QuoteParams {
    public let tokenIn: String
    public let tokenOut: String
    public let amountIn: UInt64
    public let slippage: Double?

    public init(tokenIn: String, tokenOut: String, amountIn: UInt64, slippage: Double? = nil) {
        self.tokenIn = tokenIn
        self.tokenOut = tokenOut
        self.amountIn = amountIn
        self.slippage = slippage
    }
}

public struct SwapParams {
    public let tokenIn: String
    public let tokenOut: String
    public let amountIn: UInt64
    public let minAmountOut: UInt64
    public let deadline: Int?
    public let recipient: String?

    public init(tokenIn: String, tokenOut: String, amountIn: UInt64, minAmountOut: UInt64, deadline: Int? = nil, recipient: String? = nil) {
        self.tokenIn = tokenIn
        self.tokenOut = tokenOut
        self.amountIn = amountIn
        self.minAmountOut = minAmountOut
        self.deadline = deadline
        self.recipient = recipient
    }
}

public struct SwapResult: Codable {
    public let transactionHash: String
    public let amountIn: String
    public let amountOut: String
    public let effectivePrice: Double
    public let feePaid: String
    public let route: [String]

    enum CodingKeys: String, CodingKey {
        case route
        case transactionHash = "transaction_hash"
        case amountIn = "amount_in"
        case amountOut = "amount_out"
        case effectivePrice = "effective_price"
        case feePaid = "fee_paid"
    }
}

public struct AddLiquidityParams {
    public let tokenA: String
    public let tokenB: String
    public let amountA: UInt64
    public let amountB: UInt64
    public let minAmountA: UInt64?
    public let minAmountB: UInt64?
    public let deadline: Int?

    public init(tokenA: String, tokenB: String, amountA: UInt64, amountB: UInt64, minAmountA: UInt64? = nil, minAmountB: UInt64? = nil, deadline: Int? = nil) {
        self.tokenA = tokenA
        self.tokenB = tokenB
        self.amountA = amountA
        self.amountB = amountB
        self.minAmountA = minAmountA
        self.minAmountB = minAmountB
        self.deadline = deadline
    }
}

public struct RemoveLiquidityParams {
    public let pool: String
    public let lpAmount: UInt64
    public let minAmountA: UInt64?
    public let minAmountB: UInt64?
    public let deadline: Int?

    public init(pool: String, lpAmount: UInt64, minAmountA: UInt64? = nil, minAmountB: UInt64? = nil, deadline: Int? = nil) {
        self.pool = pool
        self.lpAmount = lpAmount
        self.minAmountA = minAmountA
        self.minAmountB = minAmountB
        self.deadline = deadline
    }
}

public struct LiquidityResult: Codable {
    public let transactionHash: String
    public let amountA: String
    public let amountB: String
    public let lpTokens: String
    public let poolShare: Double

    enum CodingKeys: String, CodingKey {
        case transactionHash = "transaction_hash"
        case amountA = "amount_a"
        case amountB = "amount_b"
        case lpTokens = "lp_tokens"
        case poolShare = "pool_share"
    }
}

public struct LPPosition: Codable {
    public let poolId: String
    public let lpTokens: String
    public let tokenAAmount: String
    public let tokenBAmount: String
    public let valueUsd: Double
    public let unclaimedFeesA: String
    public let unclaimedFeesB: String
    public let impermanentLoss: Double

    enum CodingKeys: String, CodingKey {
        case poolId = "pool_id"
        case lpTokens = "lp_tokens"
        case tokenAAmount = "token_a_amount"
        case tokenBAmount = "token_b_amount"
        case valueUsd = "value_usd"
        case unclaimedFeesA = "unclaimed_fees_a"
        case unclaimedFeesB = "unclaimed_fees_b"
        case impermanentLoss = "impermanent_loss"
    }
}

public struct PerpMarket: Codable {
    public let symbol: String
    public let baseAsset: String
    public let quoteAsset: String
    public let indexPrice: Double
    public let markPrice: Double
    public let fundingRate: Double
    public let nextFundingTime: Int
    public let openInterest: String
    public let volume24h: Double
    public let maxLeverage: Int

    enum CodingKeys: String, CodingKey {
        case symbol
        case baseAsset = "base_asset"
        case quoteAsset = "quote_asset"
        case indexPrice = "index_price"
        case markPrice = "mark_price"
        case fundingRate = "funding_rate"
        case nextFundingTime = "next_funding_time"
        case openInterest = "open_interest"
        case volume24h = "volume_24h"
        case maxLeverage = "max_leverage"
    }
}

public struct OpenPositionParams {
    public let market: String
    public let side: PositionSide
    public let size: UInt64
    public let leverage: Int
    public let orderType: OrderType
    public let limitPrice: Double?
    public let stopLoss: Double?
    public let takeProfit: Double?
    public let marginType: MarginType
    public let reduceOnly: Bool

    public init(market: String, side: PositionSide, size: UInt64, leverage: Int, orderType: OrderType, limitPrice: Double? = nil, stopLoss: Double? = nil, takeProfit: Double? = nil, marginType: MarginType = .cross, reduceOnly: Bool = false) {
        self.market = market
        self.side = side
        self.size = size
        self.leverage = leverage
        self.orderType = orderType
        self.limitPrice = limitPrice
        self.stopLoss = stopLoss
        self.takeProfit = takeProfit
        self.marginType = marginType
        self.reduceOnly = reduceOnly
    }
}

public struct ClosePositionParams {
    public let market: String
    public let size: UInt64?
    public let orderType: OrderType
    public let limitPrice: Double?

    public init(market: String, size: UInt64? = nil, orderType: OrderType = .market, limitPrice: Double? = nil) {
        self.market = market
        self.size = size
        self.orderType = orderType
        self.limitPrice = limitPrice
    }
}

public struct PerpPosition: Codable {
    public let id: String
    public let market: String
    public let side: PositionSide
    public let size: String
    public let entryPrice: Double
    public let markPrice: Double
    public let liquidationPrice: Double
    public let margin: String
    public let leverage: Int
    public let unrealizedPnl: String

    enum CodingKeys: String, CodingKey {
        case id, market, side, size, margin, leverage
        case entryPrice = "entry_price"
        case markPrice = "mark_price"
        case liquidationPrice = "liquidation_price"
        case unrealizedPnl = "unrealized_pnl"
    }
}

public struct PerpOrder: Codable {
    public let id: String
    public let market: String
    public let side: PositionSide
    public let orderType: OrderType
    public let size: String
    public let price: Double?
    public let status: OrderStatus

    enum CodingKeys: String, CodingKey {
        case id, market, side, size, price, status
        case orderType = "order_type"
    }
}

public struct FundingPayment: Codable {
    public let market: String
    public let amount: String
    public let rate: Double
    public let positionSize: String
    public let timestamp: Int

    enum CodingKeys: String, CodingKey {
        case market, amount, rate, timestamp
        case positionSize = "position_size"
    }
}

public struct OrderBookEntry: Codable {
    public let price: Double
    public let size: String
    public let orders: Int
}

public struct OrderBook: Codable {
    public let market: String
    public let bids: [OrderBookEntry]
    public let asks: [OrderBookEntry]
    public let timestamp: Int
}

public struct LimitOrderParams {
    public let market: String
    public let side: String
    public let price: Double
    public let size: UInt64
    public let timeInForce: TimeInForce
    public let postOnly: Bool

    public init(market: String, side: String, price: Double, size: UInt64, timeInForce: TimeInForce = .GTC, postOnly: Bool = false) {
        self.market = market
        self.side = side
        self.price = price
        self.size = size
        self.timeInForce = timeInForce
        self.postOnly = postOnly
    }
}

public struct Order: Codable {
    public let id: String
    public let market: String
    public let side: String
    public let price: Double
    public let size: String
    public let filledSize: String
    public let status: OrderStatus
    public let timeInForce: TimeInForce
    public let postOnly: Bool

    enum CodingKeys: String, CodingKey {
        case id, market, side, price, size, status
        case filledSize = "filled_size"
        case timeInForce = "time_in_force"
        case postOnly = "post_only"
    }
}

public struct Farm: Codable {
    public let id: String
    public let name: String
    public let stakeToken: Token
    public let rewardTokens: [Token]
    public let tvlUsd: Double
    public let apr: Double

    enum CodingKeys: String, CodingKey {
        case id, name, apr
        case stakeToken = "stake_token"
        case rewardTokens = "reward_tokens"
        case tvlUsd = "tvl_usd"
    }
}

public struct StakeParams {
    public let farm: String
    public let amount: UInt64

    public init(farm: String, amount: UInt64) {
        self.farm = farm
        self.amount = amount
    }
}

public struct FarmPosition: Codable {
    public let farmId: String
    public let stakedAmount: String
    public let pendingRewards: [String]
    public let stakedAt: Int

    enum CodingKeys: String, CodingKey {
        case farmId = "farm_id"
        case stakedAmount = "staked_amount"
        case pendingRewards = "pending_rewards"
        case stakedAt = "staked_at"
    }
}

public struct OHLCV: Codable {
    public let timestamp: Int
    public let open: Double
    public let high: Double
    public let low: Double
    public let close: Double
    public let volume: Double
}

public struct TradeHistory: Codable {
    public let id: String
    public let market: String
    public let side: String
    public let price: Double
    public let size: String
    public let timestamp: Int
    public let maker: String
    public let taker: String
}

public struct VolumeStats: Codable {
    public let volume24h: Double
    public let volume7d: Double
    public let volume30d: Double
    public let trades24h: Int

    enum CodingKeys: String, CodingKey {
        case trades24h = "trades_24h"
        case volume24h = "volume_24h"
        case volume7d = "volume_7d"
        case volume30d = "volume_30d"
    }
}

public struct TVLStats: Codable {
    public let totalTvl: Double
    public let poolsTvl: Double
    public let farmsTvl: Double
    public let perpsTvl: Double

    enum CodingKeys: String, CodingKey {
        case totalTvl = "total_tvl"
        case poolsTvl = "pools_tvl"
        case farmsTvl = "farms_tvl"
        case perpsTvl = "perps_tvl"
    }
}
