//! Market types for trading venues and signals
//!
//! Contains MarketRegime, TickType, Exchange, MarketTick, TradingSignal, and OrderRef.

use serde::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr;
use uuid::Uuid;

use crate::error::CommonError;
use super::{
    CommonTypeError, HftTimestamp, Order, OrderId, OrderSide, OrderType, Price, Quantity, Symbol,
};

// =============================================================================
// MARKET TYPES (MIGRATED FROM TRADING_ENGINE)
// =============================================================================

/// Market regime enumeration for position sizing scaling and risk management
#[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,
    /// High volatility market conditions
    HighVolatility,
    /// Low volatility market conditions
    LowVolatility,
    /// Volatile market conditions (alias for `HighVolatility`)
    Volatile,
    /// Calm market conditions (alias for `LowVolatility`)
    Calm,
    /// Unknown/unclassified regime
    Unknown,
    /// Recovery regime - transitioning from crisis
    Recovery,
    /// Bubble regime - unsustainable upward movement
    Bubble,
    /// Correction regime - temporary downward adjustment
    Correction,
    /// Custom regime with numeric identifier
    Custom(usize),
}

impl Default for MarketRegime {
    fn default() -> Self {
        Self::Normal
    }
}

impl fmt::Display for MarketRegime {
    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"),
            Self::HighVolatility => write!(f, "HighVolatility"),
            Self::LowVolatility => write!(f, "LowVolatility"),
            Self::Volatile => write!(f, "Volatile"),
            Self::Calm => write!(f, "Calm"),
            Self::Unknown => write!(f, "Unknown"),
            Self::Recovery => write!(f, "Recovery"),
            Self::Bubble => write!(f, "Bubble"),
            Self::Correction => write!(f, "Correction"),
            Self::Custom(id) => write!(f, "Custom({id})"),
        }
    }
}

/// Tick type enumeration 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 execution tick
    Trade,
    /// Bid price update tick
    Bid,
    /// Ask price update tick
    Ask,
    /// Quote (bid/ask) update tick
    Quote,
}

/// Exchange enumeration for trading venues
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Exchange {
    /// New York Stock Exchange
    NYSE,
    /// NASDAQ
    NASDAQ,
    /// Chicago Mercantile Exchange
    CME,
    /// Intercontinental Exchange
    ICE,
    /// London Stock Exchange
    LSE,
    /// Tokyo Stock Exchange
    TSE,
    /// Hong Kong Stock Exchange
    HKEX,
    /// Shanghai Stock Exchange
    SSE,
    /// Shenzhen Stock Exchange
    SZSE,
    /// Euronext
    EURONEXT,
    /// Deutsche Borse
    XETRA,
    /// Chicago Board of Trade
    CBOT,
    /// Chicago Board Options Exchange
    CBOE,
    /// BATS Global Markets
    BATS,
    /// IEX Exchange
    IEX,
    /// Interactive Brokers
    IBKR,
    /// IC Markets
    ICMARKETS,
    /// Forex.com
    FOREX,
    /// Binance
    BINANCE,
    /// Coinbase
    COINBASE,
    /// Kraken
    KRAKEN,
    /// Unknown or unrecognized exchange
    UNKNOWN,
}

impl Default for Exchange {
    fn default() -> Self {
        Self::UNKNOWN
    }
}

impl fmt::Display for Exchange {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NYSE => write!(f, "NYSE"),
            Self::NASDAQ => write!(f, "NASDAQ"),
            Self::CME => write!(f, "CME"),
            Self::ICE => write!(f, "ICE"),
            Self::LSE => write!(f, "LSE"),
            Self::TSE => write!(f, "TSE"),
            Self::HKEX => write!(f, "HKEX"),
            Self::SSE => write!(f, "SSE"),
            Self::SZSE => write!(f, "SZSE"),
            Self::EURONEXT => write!(f, "EURONEXT"),
            Self::XETRA => write!(f, "XETRA"),
            Self::CBOT => write!(f, "CBOT"),
            Self::CBOE => write!(f, "CBOE"),
            Self::BATS => write!(f, "BATS"),
            Self::IEX => write!(f, "IEX"),
            Self::IBKR => write!(f, "IBKR"),
            Self::ICMARKETS => write!(f, "ICMARKETS"),
            Self::FOREX => write!(f, "FOREX"),
            Self::BINANCE => write!(f, "BINANCE"),
            Self::COINBASE => write!(f, "COINBASE"),
            Self::KRAKEN => write!(f, "KRAKEN"),
            Self::UNKNOWN => write!(f, "UNKNOWN"),
        }
    }
}

impl FromStr for Exchange {
    type Err = CommonTypeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "NYSE" => Ok(Self::NYSE),
            "NASDAQ" => Ok(Self::NASDAQ),
            "CME" => Ok(Self::CME),
            "ICE" => Ok(Self::ICE),
            "LSE" => Ok(Self::LSE),
            "TSE" => Ok(Self::TSE),
            "HKEX" => Ok(Self::HKEX),
            "SSE" => Ok(Self::SSE),
            "SZSE" => Ok(Self::SZSE),
            "EURONEXT" => Ok(Self::EURONEXT),
            "XETRA" => Ok(Self::XETRA),
            "CBOT" => Ok(Self::CBOT),
            "CBOE" => Ok(Self::CBOE),
            "BATS" => Ok(Self::BATS),
            "IEX" => Ok(Self::IEX),
            "IBKR" => Ok(Self::IBKR),
            "ICMARKETS" => Ok(Self::ICMARKETS),
            "FOREX" => Ok(Self::FOREX),
            "BINANCE" => Ok(Self::BINANCE),
            "COINBASE" => Ok(Self::COINBASE),
            "KRAKEN" => Ok(Self::KRAKEN),
            "UNKNOWN" => Ok(Self::UNKNOWN),
            _ => Ok(Self::UNKNOWN), // Default to UNKNOWN for unrecognized exchanges
        }
    }
}

/// Market tick data structure - CANONICAL SINGLE SOURCE OF TRUTH
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MarketTick {
    /// Trading symbol
    pub symbol: Symbol,
    /// Tick price
    pub price: Price,
    /// Tick size/quantity
    pub size: Quantity,
    /// Tick timestamp
    pub timestamp: HftTimestamp,
    /// Type of tick (trade, bid, ask, quote)
    pub tick_type: TickType,
    /// Exchange where the tick occurred
    pub exchange: Exchange,
    /// Sequence number for ordering
    pub sequence_number: u64,
}

impl MarketTick {
    /// Create a new market tick with current timestamp
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn new(
        symbol: Symbol,
        price: Price,
        size: Quantity,
        tick_type: TickType,
        exchange: Exchange,
        sequence_number: u64,
    ) -> Result<Self, CommonError> {
        Ok(Self {
            symbol,
            price,
            size,
            timestamp: HftTimestamp::now()?,
            tick_type,
            exchange,
            sequence_number,
        })
    }

    /// Create a new market tick with specified timestamp (for backtesting)
    #[must_use]
    pub const fn with_timestamp(
        symbol: Symbol,
        price: Price,
        size: Quantity,
        timestamp: HftTimestamp,
        tick_type: TickType,
        exchange: Exchange,
        sequence_number: u64,
    ) -> Self {
        Self {
            symbol,
            price,
            size,
            timestamp,
            tick_type,
            exchange,
            sequence_number,
        }
    }
}

/// Trading signal for algorithmic trading
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TradingSignal {
    /// Signal ID
    pub signal_id: Uuid,
    /// Symbol this signal applies to
    pub symbol: Symbol,
    /// Signal strength (-1.0 to 1.0)
    pub strength: f64,
    /// Signal direction
    pub direction: OrderSide,
    /// Confidence level (0.0 to 1.0)
    pub confidence: f64,
    /// Signal generation timestamp
    pub timestamp: HftTimestamp,
    /// Signal source/strategy
    pub source: String,
    /// Additional metadata
    pub metadata: std::collections::HashMap<String, String>,
}

impl TradingSignal {
    /// Create a new trading signal
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn new(
        symbol: Symbol,
        strength: f64,
        direction: OrderSide,
        confidence: f64,
        source: String,
    ) -> Result<Self, CommonTypeError> {
        if !(0.0_f64..=1.0_f64).contains(&confidence) {
            return Err(CommonTypeError::ValidationError {
                field: "confidence".to_owned(),
                reason: "Confidence must be between 0.0 and 1.0".to_owned(),
            });
        }
        if !(-1.0_f64..=1.0_f64).contains(&strength) {
            return Err(CommonTypeError::ValidationError {
                field: "strength".to_owned(),
                reason: "Strength must be between -1.0 and 1.0".to_owned(),
            });
        }

        Ok(Self {
            signal_id: Uuid::new_v4(),
            symbol,
            strength,
            direction,
            confidence,
            timestamp: HftTimestamp::now_common()?,
            source,
            metadata: std::collections::HashMap::new(),
        })
    }

    /// Add metadata to the signal
    #[must_use]
    pub fn with_metadata(mut self, key: String, value: String) -> Self {
        self.metadata.insert(key, value);
        self
    }
}

// =============================================================================
// HIGH-PERFORMANCE TYPES FOR COPY/CLONE OPTIMIZATION
// =============================================================================

/// Lightweight Order reference for high-performance contexts requiring Copy trait
///
/// This struct contains only the essential order data needed for performance-critical
/// operations like `SmallBatchRing` processing, while maintaining Copy semantics.
///
/// For full order details, use the complete Order struct.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct OrderRef {
    /// Order ID (u64 for performance)
    pub id: u64,
    /// Symbol hash for fast lookups
    pub symbol_hash: i64,
    /// Order side (Buy/Sell)
    pub side: OrderSide,
    /// Order type
    pub order_type: OrderType,
    /// Quantity (fixed-point u64)
    pub quantity: u64,
    /// Price (fixed-point u64, 0 for market orders)
    pub price: u64,
    /// Timestamp (nanoseconds since epoch)
    pub timestamp: u64,
}

impl OrderRef {
    /// Create `OrderRef` from a full Order struct
    #[must_use]
    pub fn from_order(order: &Order) -> Self {
        Self {
            id: order.id.value(),
            symbol_hash: order.symbol_hash(),
            side: order.side,
            order_type: order.order_type,
            quantity: order.quantity.raw_value(),
            price: order.price.map_or(0, |p| p.raw_value()),
            timestamp: order.created_at.nanos(),
        }
    }

    /// Create a limit order reference
    #[must_use]
    pub fn limit(symbol_hash: i64, side: OrderSide, quantity: u64, price: u64) -> Self {
        Self {
            id: OrderId::new().value(),
            symbol_hash,
            side,
            order_type: OrderType::Limit,
            quantity,
            price,
            timestamp: HftTimestamp::now_or_zero().nanos(),
        }
    }

    /// Create a market order reference
    #[must_use]
    pub fn market(symbol_hash: i64, side: OrderSide, quantity: u64) -> Self {
        Self {
            id: OrderId::new().value(),
            symbol_hash,
            side,
            order_type: OrderType::Market,
            quantity,
            price: 0,
            timestamp: HftTimestamp::now_or_zero().nanos(),
        }
    }

    /// Get quantity as Quantity type
    #[must_use]
    pub const fn get_quantity(&self) -> Quantity {
        Quantity::from_raw(self.quantity)
    }

    /// Get price as Price type (None for market orders)
    #[must_use]
    pub const fn get_price(&self) -> Option<Price> {
        if self.price == 0 {
            None
        } else {
            Some(Price::from_raw(self.price))
        }
    }

    /// Check if this is a buy order
    #[must_use]
    pub fn is_buy(&self) -> bool {
        self.side == OrderSide::Buy
    }

    /// Check if this is a sell order
    #[must_use]
    pub fn is_sell(&self) -> bool {
        self.side == OrderSide::Sell
    }

    /// Check if this is a market order
    #[must_use]
    pub fn is_market_order(&self) -> bool {
        self.order_type == OrderType::Market || self.price == 0
    }

    /// Check if this is a limit order
    #[must_use]
    pub fn is_limit_order(&self) -> bool {
        self.order_type == OrderType::Limit && self.price > 0
    }
}

impl Default for OrderRef {
    fn default() -> Self {
        Self {
            id: 0,
            symbol_hash: 0,
            side: OrderSide::Buy,
            order_type: OrderType::Market,
            quantity: 0,
            price: 0,
            timestamp: 0,
        }
    }
}
