//! Order test fixtures
//!
//! Provides mock order and trade builders used across 22+ test files.

use chrono::{DateTime, Utc};
use uuid::Uuid;

/// Mock order builder for testing
///
/// Pattern found in 22+ test files with `create_mock_order()` functions.
pub struct MockOrderBuilder {
    symbol: String,
    quantity: f64,
    price: Option<f64>,
    side: Side,
    order_type: OrderType,
    status: OrderStatus,
    timestamp: DateTime<Utc>,
}

#[derive(Clone, Copy, Debug)]
pub enum Side {
    Buy,
    Sell,
}

#[derive(Clone, Copy, Debug)]
pub enum OrderType {
    Market,
    Limit,
    Stop,
    StopLimit,
}

#[derive(Clone, Copy, Debug)]
pub enum OrderStatus {
    Pending,
    PartiallyFilled,
    Filled,
    Cancelled,
    Rejected,
}

#[derive(Clone, Debug)]
pub struct MockOrder {
    pub id: String,
    pub symbol: String,
    pub quantity: f64,
    pub price: Option<f64>,
    pub side: Side,
    pub order_type: OrderType,
    pub status: OrderStatus,
    pub timestamp: DateTime<Utc>,
    pub filled_quantity: f64,
    pub average_fill_price: Option<f64>,
}

impl MockOrderBuilder {
    /// Create a new order builder with defaults
    pub fn new() -> Self {
        Self {
            symbol: "AAPL".to_string(),
            quantity: 100.0,
            price: None,
            side: Side::Buy,
            order_type: OrderType::Market,
            status: OrderStatus::Pending,
            timestamp: Utc::now(),
        }
    }

    /// Set the symbol
    pub fn symbol(mut self, symbol: &str) -> Self {
        self.symbol = symbol.to_string();
        self
    }

    /// Set buy side
    pub fn buy(mut self) -> Self {
        self.side = Side::Buy;
        self
    }

    /// Set sell side
    pub fn sell(mut self) -> Self {
        self.side = Side::Sell;
        self
    }

    /// Set quantity
    pub fn quantity(mut self, quantity: f64) -> Self {
        self.quantity = quantity;
        self
    }

    /// Set limit price
    pub fn limit_price(mut self, price: f64) -> Self {
        self.price = Some(price);
        self.order_type = OrderType::Limit;
        self
    }

    /// Set as market order
    pub fn market(mut self) -> Self {
        self.order_type = OrderType::Market;
        self.price = None;
        self
    }

    /// Set as filled
    pub fn filled(mut self) -> Self {
        self.status = OrderStatus::Filled;
        self
    }

    /// Build the mock order
    pub fn build(self) -> MockOrder {
        let is_filled = matches!(self.status, OrderStatus::Filled);
        MockOrder {
            id: Uuid::new_v4().to_string(),
            symbol: self.symbol,
            quantity: self.quantity,
            price: self.price,
            side: self.side,
            order_type: self.order_type,
            status: self.status,
            timestamp: self.timestamp,
            filled_quantity: if is_filled { self.quantity } else { 0.0 },
            average_fill_price: self.price,
        }
    }
}

impl Default for MockOrderBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Mock trade builder
pub struct MockTradeBuilder {
    symbol: String,
    price: f64,
    quantity: f64,
    side: Side,
    timestamp: DateTime<Utc>,
}

#[derive(Clone, Debug)]
pub struct MockTrade {
    pub id: String,
    pub symbol: String,
    pub price: f64,
    pub quantity: f64,
    pub side: Side,
    pub timestamp: DateTime<Utc>,
}

impl MockTradeBuilder {
    pub fn new() -> Self {
        Self {
            symbol: "AAPL".to_string(),
            price: 150.0,
            quantity: 100.0,
            side: Side::Buy,
            timestamp: Utc::now(),
        }
    }

    pub fn symbol(mut self, symbol: &str) -> Self {
        self.symbol = symbol.to_string();
        self
    }

    pub fn price(mut self, price: f64) -> Self {
        self.price = price;
        self
    }

    pub fn quantity(mut self, quantity: f64) -> Self {
        self.quantity = quantity;
        self
    }

    pub fn buy(mut self) -> Self {
        self.side = Side::Buy;
        self
    }

    pub fn sell(mut self) -> Self {
        self.side = Side::Sell;
        self
    }

    pub fn build(self) -> MockTrade {
        MockTrade {
            id: Uuid::new_v4().to_string(),
            symbol: self.symbol,
            price: self.price,
            quantity: self.quantity,
            side: self.side,
            timestamp: self.timestamp,
        }
    }
}

impl Default for MockTradeBuilder {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_order_builder_defaults() {
        let order = MockOrderBuilder::new().build();
        assert_eq!(order.symbol, "AAPL");
        assert_eq!(order.quantity, 100.0);
        assert!(matches!(order.side, Side::Buy));
    }

    #[test]
    fn test_order_builder_customization() {
        let order = MockOrderBuilder::new()
            .symbol("TSLA")
            .sell()
            .quantity(50.0)
            .limit_price(200.0)
            .filled()
            .build();

        assert_eq!(order.symbol, "TSLA");
        assert_eq!(order.quantity, 50.0);
        assert!(matches!(order.side, Side::Sell));
        assert_eq!(order.price, Some(200.0));
        assert!(matches!(order.status, OrderStatus::Filled));
        assert_eq!(order.filled_quantity, 50.0);
    }

    #[test]
    fn test_trade_builder() {
        let trade = MockTradeBuilder::new()
            .symbol("NVDA")
            .price(450.0)
            .quantity(25.0)
            .sell()
            .build();

        assert_eq!(trade.symbol, "NVDA");
        assert_eq!(trade.price, 450.0);
        assert_eq!(trade.quantity, 25.0);
        assert!(matches!(trade.side, Side::Sell));
    }
}
