use crate::{
    OrderId,
    domain::{
        book::{
            Price,
            Quantity,
        },
        event::*,
        trade::TradeId,
    },
    fuel_types::{
        BlockHeight,
        Bytes32,
        ContractId,
        TxId,
        TxPointer,
    },
    parse::HexDisplayFromStr,
    primitives::{
        OrderType,
        Side,
    },
};
use serde::Serialize;
use serde_with::{
    DisplayFromStr,
    serde_as,
};

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct EventPrimaryKey {
    pub tx_pointer: TxPointer,
    pub receipt_index: u16,
}

#[serde_as]
#[derive(Debug, serde::Serialize)]
pub struct BlockChainEventResponse<Event> {
    pub primary_key: EventPrimaryKey,
    #[serde_as(as = "HexDisplayFromStr")]
    pub contract_id: ContractId,
    pub event: Event,
}

#[derive(Debug, serde::Serialize)]
pub struct OrderCreatedEventResponse {
    pub order_id: OrderId,
    pub trader_id: Identity,
    pub order_side: Side,
    pub order_type: OrderType,
    pub quantity: Quantity,
    pub price: Price,
}

#[derive(Debug, serde::Serialize)]
pub struct OrderMatchedEventResponse {
    pub trade_id: TradeId,
    pub quantity: Quantity,
    pub price: Price,
}

#[derive(Debug, serde::Serialize)]
pub struct OrderCancelledEventResponse {
    pub order_id: Bytes32,
    pub reason: CancellationReason,
}

#[derive(Debug, serde::Serialize)]
pub struct EndOfMarketOrderEventResponse {
    pub order_id: Bytes32,
}

#[derive(Debug, serde::Serialize, strum_macros::AsRefStr)]
#[strum(serialize_all = "snake_case")]
pub enum EventV1Response {
    BalanceIncrease(BlockChainEventResponse<BalanceIncrease>),
    BalanceDecrease(BlockChainEventResponse<BalanceDecrease>),
    OrderCreated(BlockChainEventResponse<OrderCreatedEventResponse>),
    OrderCanceled(BlockChainEventResponse<OrderCancelledEventResponse>),
    EndOfMarketOrder(BlockChainEventResponse<EndOfMarketOrderEventResponse>),
    TradePerformed(BlockChainEventResponse<OrderMatchedEventResponse>),
    Withdrawal(BlockChainEventResponse<WithdrawSettledTradeEvent>),
    Configuration(BlockChainEventResponse<OrderBookConfigEvent>),
    ConfigurationSymbols(BlockChainEventResponse<OrderBookSymbolsEvent>),
    ConfigurationWhitelist(BlockChainEventResponse<OrderBookWhitelistEvent>),
    ConfigurationBlacklist(BlockChainEventResponse<OrderBookBlacklistEvent>),
    NonceChange(BlockChainEventResponse<NonceChangeEvent>),
    TradeAccountRegistration(BlockChainEventResponse<TradeAccountRegistered>),
    TradeAccountReferer(BlockChainEventResponse<TradeAccountReferer>),
    OrderBookRegistration(BlockChainEventResponse<OrderBookRegistered>),
    PauseEvent(BlockChainEventResponse<PauseEvent>),
    UnpauseEvent(BlockChainEventResponse<UnpauseEvent>),
    FeesClaimedEvent(BlockChainEventResponse<FeesClaimedEvent>),
    SessionCreated(BlockChainEventResponse<SessionCreated>),
    SessionRevoked(BlockChainEventResponse<SessionRevoked>),
}

#[derive(serde::Serialize, Debug)]
pub enum EventResponse {
    EventV1(EventV1Response),
}

#[serde_as]
#[derive(Serialize, Debug)]
pub struct TransactionEventsResponse {
    #[serde_as(as = "HexDisplayFromStr")]
    pub tx_id: TxId,
    pub events: Vec<EventResponse>,
}

#[serde_as]
#[derive(Serialize, Debug)]
pub struct HeaderResponse {
    pub block_height: BlockHeight,
    #[serde_as(as = "DisplayFromStr")]
    pub timestamp: u128,
}

#[derive(Serialize, Debug)]
pub struct GetEventsResponse {
    pub header: HeaderResponse,
    pub events: Vec<TransactionEventsResponse>,
}
