use num_bigint::BigUint;
use serde::{Deserialize, Serialize};

use crate::{AssetAmount, MarketId, OrderId};

/// Order side
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum OrderSide {
    /// Ask
    /// Note: Ask means sell base asset
    Ask = 1,

    /// Bid
    /// Note: Bid means buy base asset
    Bid = 2,
}

/// Spot order detail
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct SpotOrderDetail {
    /// Order side
    pub side: OrderSide,

    /// Order price
    pub price: BigUint,

    /// Order volume
    /// Note: volume means base asset quantity
    pub volume: BigUint,
}

/// SwapV2 exact tokens
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum SwapV2ExactTokens {
    /// Exact input
    ExactInput {
        /// Input amount
        /// Note: input amount means the input asset quantity
        input_amount: AssetAmount,
        /// Min out
        /// Note: min out means the output asset quantity must be greater than or equal to the min out
        min_out: AssetAmount,
    },

    /// Exact output
    ExactOutput {
        /// Output amount
        /// Note: output amount means the output asset quantity
        output_amount: AssetAmount,
        /// Max in
        /// Note: max in means the input asset quantity must be less than or equal to the max in
        max_in: AssetAmount,
    },
}

/// SwapV2 order detail
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct SwapV2OrderDetail {
    /// Order side
    pub side: OrderSide,

    /// Exact tokens
    pub exact_tokens: SwapV2ExactTokens,
}

/// Order detail
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum OrderDetail {
    /// Spot order detail
    Spot(SpotOrderDetail),

    /// SwapV2 order detail
    SwapV2(SwapV2OrderDetail),
}

/// Submit spot order
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct SubmitOrder {
    /// Market id
    market_id: MarketId,

    /// Order detail
    order_detail: OrderDetail,
}

/// Order scope
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum OrderScope {
    /// Exact order id
    Exact(OrderId),

    /// Side
    Side(OrderSide),

    /// All
    /// Note: all means all orders
    All,
}

/// Cancel order
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct CancelOrder {
    /// Market id
    market_id: MarketId,

    /// Cancel order scope
    scope: OrderScope,
}

/// Add liquidity
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct AddLiquidity {
    /// Market id
    market_id: MarketId,

    /// Base asset quantity
    base_asset_quantity: AssetAmount,

    /// Quote asset quantity
    quote_asset_quantity: AssetAmount,
}

/// Remove liquidity
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct RemoveLiquidity {
    /// Market id
    market_id: MarketId,

    /// Liquidity token quantity
    liquidity_token_quantity: AssetAmount,
}
