use betex::{
    book::protocol::{
        command::{BinarySide, BinaryTimeInForce, MarketState, Persistence, Side, TimeInForce},
        response::{Response, TradeSummary},
    },
    snapshot::MarketSnapshot,
    types::{
        AccountId, CorrelationId, MarketId, MarketKind, MarketModel, MarketPhase, OddsX10000,
        OrderId, RunnerId,
    },
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, strum::Display)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum MarketStatus {
    Active,
    Closed,
    Settled,
    Voided,
}

impl MarketStatus {
    pub fn is_terminal(&self) -> bool {
        matches!(self, Self::Settled | Self::Voided)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarketInfo {
    pub market_id: MarketId,
    pub engine_id: Uuid,
    pub name: String,
    pub market_model: MarketModel,
    pub market_kind: MarketKind,
    pub market_phase: MarketPhase,
    pub runner_ids: Vec<RunnerId>,
    pub runner_labels: Vec<String>,
    pub status: MarketStatus,
    pub created_at: i64,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ClientMsg {
    // Admin commands
    SetMarketState {
        #[serde(default)]
        market_id: Option<MarketId>,
        state: MarketState,
    },
    SetMarketPhase {
        #[serde(default)]
        market_id: Option<MarketId>,
        phase: MarketPhase,
    },
    CloseMarket {
        #[serde(default)]
        market_id: Option<MarketId>,
        batch_max_events: u16,
    },
    BatchCancelOrders {
        #[serde(default)]
        correlation_id: Option<CorrelationId>,
        #[serde(default)]
        market_id: Option<MarketId>,
        #[serde(default)]
        from_created_at_inclusive_ms: Option<i64>,
        #[serde(default)]
        to_created_at_inclusive_ms: Option<i64>,
        #[serde(default)]
        account_id: Option<AccountId>,
        #[serde(default)]
        runner_id: Option<RunnerId>,
        batch_max_events: u16,
        reason: String,
        #[serde(default)]
        metadata: Option<serde_json::Value>,
    },
    ContinueBatchCancelOrders {
        #[serde(default)]
        correlation_id: Option<CorrelationId>,
        #[serde(default)]
        market_id: Option<MarketId>,
    },
    SettleMarket {
        #[serde(default)]
        market_id: Option<MarketId>,
        winner_runner_id: RunnerId,
    },
    VoidMarket {
        #[serde(default)]
        market_id: Option<MarketId>,
        reason: Option<String>,
    },
    HaltMarket {
        #[serde(default)]
        market_id: Option<MarketId>,
        reason: u32,
    },
    ResumeMarket {
        #[serde(default)]
        market_id: Option<MarketId>,
    },
    Ping,

    // Market lifecycle (control plane)
    CreateMarket {
        name: String,
        #[serde(default)]
        market_model: MarketModel,
        market_kind: MarketKind,
        market_phase: MarketPhase,
        runner_ids: Vec<RunnerId>,
        runner_labels: Vec<String>,
    },
    RemoveMarket {
        market_id: MarketId,
    },
    ListMarkets,
    Subscribe {
        market_id: MarketId,
    },

    // Trading commands
    PlaceOrder {
        #[serde(default)]
        correlation_id: Option<CorrelationId>,
        order_id: OrderId,
        market_id: MarketId,
        runner_id: RunnerId,
        account_id: AccountId,
        side: Side,
        odds: OddsX10000,
        stake: i64,
        persistence: Option<Persistence>,
        time_in_force: Option<TimeInForce>,
    },
    PlaceBinaryOrder {
        #[serde(default)]
        correlation_id: Option<CorrelationId>,
        order_id: OrderId,
        market_id: MarketId,
        account_id: AccountId,
        side: BinarySide,
        price_ticks: u16,
        qty_shares: u64,
        time_in_force: Option<BinaryTimeInForce>,
    },
    CancelOrder {
        #[serde(default)]
        correlation_id: Option<CorrelationId>,
        market_id: MarketId,
        account_id: AccountId,
        order_id: OrderId,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ServerMsg {
    Snapshot {
        snapshot: MarketSnapshot,
    },
    Status {
        global_seq: u64,
        market_count: usize,
    },
    Ack {
        ok: bool,
        response: Option<Response>,
        error: Option<String>,
    },
    OrderResponse {
        correlation_id: Option<CorrelationId>,
        ok: bool,
        order_id: Option<OrderId>,
        trades: Vec<TradeSummary>,
        error: Option<String>,
    },
    MarketCreated {
        market: MarketInfo,
    },
    MarketRemoved {
        market_id: MarketId,
    },
    MarketList {
        markets: Vec<MarketInfo>,
    },
    MarketStatusChanged {
        market_id: MarketId,
        status: MarketStatus,
    },
    MarketPhaseChanged {
        market_id: MarketId,
        phase: MarketPhase,
    },
}

pub fn encode_msg<T: Serialize + ?Sized>(value: &T) -> Result<String, serde_json::Error> {
    serde_json::to_string(value)
}

pub fn decode_msg<T>(data: &[u8]) -> Result<T, serde_json::Error>
where
    T: for<'de> Deserialize<'de>,
{
    serde_json::from_slice(data)
}
