use chrono::{DateTime, Utc};
use serde::{Serialize, Deserialize};
use std::fmt;

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

impl fmt::Display for Side {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Side::Buy => write!(f, "buy"),
            Side::Sell => write!(f, "sell"),
        }
    }
}

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

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

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TimeInForce {
    Day,
    GTC,    // Good Till Cancelled
    IOC,    // Immediate or Cancel
    FOK,    // Fill or Kill
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Order {
    pub id: String,
    pub symbol: String,
    pub side: Side,
    pub quantity: f64,
    pub order_type: OrderType,
    pub limit_price: Option<f64>,
    pub stop_price: Option<f64>,
    pub time_in_force: TimeInForce,
    pub status: OrderStatus,
    pub submitted_at: Option<DateTime<Utc>>,
    pub filled_quantity: f64,
    pub average_fill_price: Option<f64>,
}

impl Order {
    pub fn new_market_order(symbol: String, side: Side, quantity: f64) -> Self {
        Self {
            id: uuid::Uuid::new_v4().to_string(),
            symbol,
            side,
            quantity,
            order_type: OrderType::Market,
            limit_price: None,
            stop_price: None,
            time_in_force: TimeInForce::Day,
            status: OrderStatus::Pending,
            submitted_at: None,
            filled_quantity: 0.0,
            average_fill_price: None,
        }
    }
    
    pub fn new_limit_order(symbol: String, side: Side, quantity: f64, limit_price: f64) -> Self {
        Self {
            id: uuid::Uuid::new_v4().to_string(),
            symbol,
            side,
            quantity,
            order_type: OrderType::Limit,
            limit_price: Some(limit_price),
            stop_price: None,
            time_in_force: TimeInForce::Day,
            status: OrderStatus::Pending,
            submitted_at: None,
            filled_quantity: 0.0,
            average_fill_price: None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Fill {
    pub timestamp: DateTime<Utc>,
    pub price: f64,
    pub quantity: f64,
    pub commission: f64,
}