use crate::{
    OrderId,
    domain::{
        bars::SubscriptionFrequency,
        book::MarketId,
        event::Identity,
    },
    fuel_types::{
        Address,
        AssetId,
        Bytes32,
        Bytes64,
        UtxoId,
    },
};
use serde::{
    Deserialize,
    Serialize,
};
use serde_with::{
    DisplayFromStr,
    serde_as,
};

/// @TODO: Add precision based on the market pair
pub const PRECISIONS: [u64; 9] = [
    10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
];

#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "action")]
pub enum Request {
    #[serde(rename = "subscribe_depth")]
    SubscribeDepth(SubscribeDepthRequest),
    #[serde(rename = "subscribe_depth_view")]
    SubscribeDepthView(SubscribeDepthViewRequest),
    #[serde(rename = "subscribe_orders")]
    SubscribeOrders(SubscribeOrdersRequest),
    #[serde(rename = "subscribe_trades")]
    SubscribeTrades(SubscribeTradesRequest),
    #[serde(rename = "unsubscribe_depth")]
    UnsubscribeDepth(UnsubscribeDepthRequest),
    #[serde(rename = "unsubscribe_depth_view")]
    UnsubscribeDepthView(UnsubscribeDepthViewRequest),
    #[serde(rename = "unsubscribe_orders")]
    UnsubscribeOrders(UnsubscribeOrdersRequest),
    #[serde(rename = "unsubscribe_trades")]
    UnsubscribeTrades(UnsubscribeTradesRequest),
    #[serde(rename = "subscribe_balances")]
    SubscribeBalances(SubscribeBalancesRequest),
    #[serde(rename = "unsubscribe_balances")]
    UnsubscribeBalances(UnsubscribeBalancesRequest),
    #[serde(rename = "subscribe_nonce")]
    SubscribeNonce(SubscribeNonceRequest),
    #[serde(rename = "unsubscribe_nonce")]
    UnsubscribeNonce(UnsubscribeNonceRequest),
}

#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SubscribeDepthRequest {
    #[serde(default = "depth")]
    pub topic: String,
    pub market_id: MarketId,
    #[serde_as(as = "DisplayFromStr")]
    pub precision: u64,
}

#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SubscribeDepthViewRequest {
    #[serde(default = "depth")]
    pub topic: String,
    pub market_id: MarketId,
    #[serde_as(as = "DisplayFromStr")]
    pub precision: u64,
    #[serde_as(as = "DisplayFromStr")]
    pub frequency: SubscriptionFrequency,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SubscribeOrdersRequest {
    #[serde(default = "orders")]
    pub topic: String,
    pub identities: Vec<Identity>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SubscribeNonceRequest {
    #[serde(default = "nonce")]
    pub topic: String,
    pub identities: Vec<Identity>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SubscribeTradesRequest {
    #[serde(default = "trades")]
    pub topic: String,
    pub market_id: MarketId,
}

fn depth() -> String {
    "depth".to_string()
}

fn orders() -> String {
    "orders".to_string()
}

fn trades() -> String {
    "trades".to_string()
}

fn balances() -> String {
    "balances".to_string()
}

fn nonce() -> String {
    "nonce".to_string()
}

#[derive(Serialize, Deserialize, Debug)]
pub struct UnsubscribeDepthRequest {
    #[serde(default = "depth")]
    pub topic: String,
    pub market_id: MarketId,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct UnsubscribeDepthViewRequest {
    #[serde(default = "depth")]
    pub topic: String,
    pub market_id: MarketId,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct UnsubscribeOrdersRequest {
    #[serde(default = "orders")]
    pub topic: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct UnsubscribeTradesRequest {
    #[serde(default = "trades")]
    pub topic: String,
    pub market_id: MarketId,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SubscribeBalancesRequest {
    #[serde(default = "balances")]
    pub topic: String,
    pub identities: Vec<Identity>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct UnsubscribeBalancesRequest {
    #[serde(default = "balances")]
    pub topic: String,
    pub identities: Vec<Identity>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct UnsubscribeNonceRequest {
    #[serde(default = "nonce")]
    pub topic: String,
    pub identities: Vec<Identity>,
}

#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct CancelOrderRequest {
    pub market_id: MarketId,
    #[serde_as(as = "DisplayFromStr")]
    pub order_id: OrderId,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CreateLimitOrderRequest {
    pub market_id: MarketId,
    pub account: Address,
    pub inputs: Vec<UtxoId>,
    pub order: CreateLimitOrderParams,
    pub signature: Bytes64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Intent {
    pub asset_id: AssetId,
    pub amount: u64,
}

#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
pub struct CreateLimitOrderParams {
    pub side: String,
    #[serde_as(as = "DisplayFromStr")]
    pub quantity: u64,
    #[serde_as(as = "DisplayFromStr")]
    pub price: u64,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GetUtxosRequest {
    pub account: Bytes32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GetTrades {
    pub market_id: Bytes32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GetTradeDataRequest {
    pub market_id: MarketId,
    pub period: String,
}
