//! Trading-specific types and enums
//!
//! This module contains the canonical definitions for all trading-related
//! types used across the Foxhunt HFT system. This is the single source
//! of truth for all trading types.

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

// ELIMINATED: Re-exports removed to force explicit imports
// REMOVED: TimeInForce duplicate - use canonical definition from common::types

// Currency moved to canonical source: common::types::Currency

/// Tick type for market data
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "database", derive(sqlx::Type))]
#[cfg_attr(
    feature = "database",
    sqlx(type_name = "tick_type", rename_all = "snake_case")
)]
pub enum TickType {
    /// Trade tick
    Trade,
    /// Bid price update
    Bid,
    /// Ask price update
    Ask,
    /// Quote update (bid and ask)
    Quote,
}

impl fmt::Display for TickType {
    /// Format the tick type for display
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Trade => write!(f, "TRADE"),
            Self::Bid => write!(f, "BID"),
            Self::Ask => write!(f, "ASK"),
            Self::Quote => write!(f, "QUOTE"),
        }
    }
}

/// Order book action type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum BookAction {
    /// Update price level
    Update,
    /// Delete price level
    Delete,
    /// Clear entire book
    Clear,
}

impl fmt::Display for BookAction {
    /// Format the book action for display
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Update => write!(f, "UPDATE"),
            Self::Delete => write!(f, "DELETE"),
            Self::Clear => write!(f, "CLEAR"),
        }
    }
}

/// Market regime classification
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum MarketRegime {
    /// Normal market conditions
    Normal,
    /// Crisis/stress market conditions
    Crisis,
    /// Trending market (strong directional movement)
    Trending,
    /// Sideways/ranging market (low volatility)
    Sideways,
    /// Bull market (sustained upward trend)
    Bull,
    /// Bear market (sustained downward trend)
    Bear,
}

impl fmt::Display for MarketRegime {
    /// Format the market regime for display
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Normal => write!(f, "NORMAL"),
            Self::Crisis => write!(f, "CRISIS"),
            Self::Trending => write!(f, "TRENDING"),
            Self::Sideways => write!(f, "SIDEWAYS"),
            Self::Bull => write!(f, "BULL"),
            Self::Bear => write!(f, "BEAR"),
        }
    }
}

/// Core Quantity type using fixed-point arithmetic for precise calculations
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Quantity {
    /// Internal representation using 6 decimal places (scale factor of `1_000_000`)
    value: u64,
}

impl Quantity {
    /// Scale factor for fixed-point arithmetic (6 decimal places)
    pub const SCALE: u64 = 1_000_000;

    /// Zero quantity
    pub const ZERO: Self = Self { value: 0 };

    /// Create a new quantity from a floating-point value
    ///
    /// # Errors
    /// Returns error if the operation fails
    ///
    /// # Errors
    /// Returns error if the value is negative or not finite
    #[allow(clippy::float_arithmetic)]
    pub fn new(value: f64) -> Result<Self, &'static str> {
        if value < 0.0_f64 {
            return Err("Quantity cannot be negative");
        }
        if !value.is_finite() {
            return Err("Quantity must be finite");
        }

        #[allow(clippy::as_conversions)]
        let scaled = (value * (Self::SCALE as f64)).round() as u64;

        Ok(Self { value: scaled })
    }

    /// Create from raw internal value
    pub const fn from_raw(value: u64) -> Self {
        Self { value }
    }

    /// Get raw internal value
    pub const fn raw(&self) -> u64 {
        self.value
    }

    /// Convert to floating-point value
    #[allow(clippy::float_arithmetic, clippy::as_conversions)]
    pub fn to_f64(&self) -> f64 {
        (self.value as f64) / (Self::SCALE as f64)
    }

    /// Convert to decimal
    pub fn to_decimal(&self) -> Decimal {
        Decimal::new(i64::try_from(self.value).unwrap_or(0), 6)
    }

    /// Add two quantities
    pub const fn add(&self, other: Self) -> Self {
        Self {
            value: self.value.saturating_add(other.value),
        }
    }

    /// Subtract two quantities
    pub const fn subtract(&self, other: Self) -> Self {
        Self {
            value: self.value.saturating_sub(other.value),
        }
    }
}

impl fmt::Display for Quantity {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:.6}", self.to_f64())
    }
}

impl std::ops::Add for Quantity {
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        Self {
            value: self.value.saturating_add(other.value),
        }
    }
}

impl std::ops::Sub for Quantity {
    type Output = Self;

    fn sub(self, other: Self) -> Self::Output {
        Self {
            value: self.value.saturating_sub(other.value),
        }
    }
}

/// Order event for tracking order lifecycle
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrderEvent {
    /// Unique order identifier
    pub order_id: String,
    /// Trading symbol
    pub symbol: String,
    /// Order type (Market, Limit, etc.)
    pub order_type: OrderType,
    /// Order side (Buy/Sell)
    pub side: OrderSide,
    /// Order quantity
    pub quantity: Quantity,
    /// Order price (None for market orders)
    pub price: Option<Decimal>,
    /// Event timestamp
    pub timestamp: DateTime<Utc>,
    /// Strategy identifier
    pub strategy_id: String,
    /// Type of order event
    pub event_type: OrderEventType,
    /// Previous quantity for modifications
    pub previous_quantity: Option<Quantity>,
    /// Previous price for modifications
    pub previous_price: Option<Decimal>,
    /// Reason for cancellation or modification
    pub reason: Option<String>,
}

/// Types of order events
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum OrderEventType {
    /// Order was placed
    Placed,
    /// Order was modified
    Modified,
    /// Order was cancelled
    Cancelled,
    /// Order was rejected
    Rejected,
    /// Order expired
    Expired,
}

impl fmt::Display for OrderEventType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Placed => write!(f, "PLACED"),
            Self::Modified => write!(f, "MODIFIED"),
            Self::Cancelled => write!(f, "CANCELLED"),
            Self::Rejected => write!(f, "REJECTED"),
            Self::Expired => write!(f, "EXPIRED"),
        }
    }
}

/// Order type enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum OrderType {
    /// Market order - execute immediately at best available price
    Market,
    /// Limit order - execute only at specified price or better
    Limit,
    /// Stop order - becomes market order when stop price is reached
    Stop,
    /// Stop-limit order - becomes limit order when stop price is reached
    StopLimit,
}

impl fmt::Display for OrderType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Market => write!(f, "MARKET"),
            Self::Limit => write!(f, "LIMIT"),
            Self::Stop => write!(f, "STOP"),
            Self::StopLimit => write!(f, "STOP_LIMIT"),
        }
    }
}

/// Order side enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum OrderSide {
    /// Buy order
    Buy,
    /// Sell order
    Sell,
}

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