use crate::{
    domain::book::MarketId,
    fuel_types::{
        AssetId,
        ContractId,
    },
    parse::HexDisplayFromStr,
};
use serde::{
    Deserialize,
    Serialize,
};
use serde_with::{
    DisplayFromStr,
    serde_as,
};

pub type ChainId = crate::fuel_types::Bytes32;

#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct MarketResponse {
    #[serde_as(as = "HexDisplayFromStr")]
    pub market_id: MarketId,
    #[serde_as(as = "HexDisplayFromStr")]
    pub contract_id: ContractId,
    #[serde_as(as = "Option<HexDisplayFromStr>")]
    pub whitelist_id: Option<ContractId>,
    #[serde_as(as = "Option<HexDisplayFromStr>")]
    pub blacklist_id: Option<ContractId>,
    #[serde_as(as = "DisplayFromStr")]
    pub taker_fee: u64,
    #[serde_as(as = "DisplayFromStr")]
    pub maker_fee: u64,
    #[serde_as(as = "DisplayFromStr")]
    pub min_order: u64,
    #[serde_as(as = "DisplayFromStr")]
    pub dust: u64,
    #[serde_as(as = "DisplayFromStr")]
    pub price_window: u64,
    pub base: AssetResponse,
    pub quote: AssetResponse,
}

#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct AssetResponse {
    pub symbol: String,
    #[serde_as(as = "HexDisplayFromStr")]
    pub asset: AssetId,
    pub decimals: u8,
    pub max_precision: u8,
}

#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct MarketsResponse {
    #[serde_as(as = "HexDisplayFromStr")]
    pub chain_id: ChainId,
    #[serde_as(as = "HexDisplayFromStr")]
    pub base_asset_id: AssetId,
    #[serde_as(as = "HexDisplayFromStr")]
    pub books_registry_id: ContractId,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde_as(as = "Option<HexDisplayFromStr>")]
    pub books_whitelist_id: Option<ContractId>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde_as(as = "Option<HexDisplayFromStr>")]
    pub books_blacklist_id: Option<ContractId>,
    #[serde_as(as = "HexDisplayFromStr")]
    pub accounts_registry_id: ContractId,
    #[serde_as(as = "HexDisplayFromStr")]
    pub trade_account_oracle_id: ContractId,
    #[serde_as(as = "Option<HexDisplayFromStr>")]
    pub fast_bridge_asset_registry_contract_id: Option<ContractId>,
    pub markets: Vec<MarketResponse>,
}

#[serde_as]
#[derive(Serialize, Debug, PartialEq, Clone)]
#[cfg_attr(test, derive(serde::Deserialize))]
pub struct MarketSummary {
    #[serde_as(as = "HexDisplayFromStr")]
    pub market_id: MarketId,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub last_price: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub high_price: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub low_price: Option<u64>,
    #[serde_as(as = "DisplayFromStr")]
    pub volume_24h: u128,
    #[serde_as(as = "DisplayFromStr")]
    pub change_24h: f64,
}

#[serde_as]
#[derive(Serialize, Debug, PartialEq)]
#[cfg_attr(test, derive(serde::Deserialize))]
pub struct MarketTicker {
    #[serde_as(as = "DisplayFromStr")]
    pub timestamp: u128,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub high: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub low: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub bid: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub bid_volume: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub ask: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub ask_volume: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub open: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub close: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub last: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub previous_close: Option<u64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub change: Option<f64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub percentage: Option<f64>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub average: Option<f64>,
    #[serde_as(as = "DisplayFromStr")]
    pub base_volume: u128,
    #[serde_as(as = "DisplayFromStr")]
    pub quote_volume: u128,
}

#[serde_as]
#[derive(Serialize, Debug, PartialEq)]
#[cfg_attr(test, derive(serde::Deserialize))]
pub struct MarketFees {
    #[serde_as(as = "HexDisplayFromStr")]
    pub market_id: MarketId,
    #[serde_as(as = "DisplayFromStr")]
    pub accumulated_fees_base_asset: u64,
    #[serde_as(as = "DisplayFromStr")]
    pub accumulated_fees_quote_asset: u64,
}
