//! Financial types with exact arithmetic for trading systems
//!
//! This module provides high-precision financial types with exact arithmetic
//! and proper scaling factors for financial calculations.

use std::ops::{Add, Div, Mul, Sub};

use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};

// ============================================================================
// CANONICAL DECIMAL EXPORTS - Single Source of Truth
// ============================================================================

// Re-export Decimal from rust_decimal as the canonical type for this module
// Removed pub use - import rust_decimal types directly where needed

// Note: The types::prelude module re-exports these same types as the canonical
// Decimal for the entire system. This ensures type compatibility.

// ============================================================================
// SCALING CONSTANTS - CRITICAL FOR FINANCIAL PRECISION
// ============================================================================

/// Price scaling factor (1000000 = 6 decimal places)
pub const PRICE_SCALE: i64 = 1_000_000;

/// Quantity scaling factor (1000000 = 6 decimal places)
pub const QUANTITY_SCALE: i64 = 1_000_000;

/// Money scaling factor (1000000 = 6 decimal places)
pub const MONEY_SCALE: i64 = 1_000_000;

// ============================================================================
// INTEGER PRICE TYPE - EXACT ARITHMETIC
// ============================================================================

/// High-precision `price` type using integer arithmetic
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
/// `IntegerPrice` component.
pub struct IntegerPrice(pub i64);

// TECHNICAL DEBT ELIMINATED - Use IntegerPrice directly instead of IntegerPrice alias

impl IntegerPrice {
    /// Zero `price` constant
    pub const ZERO: Self = Self(0);

    /// One `price` constant
    pub const ONE: Self = Self(PRICE_SCALE);

    /// Create from `i64` value
    #[must_use]
    pub const fn from_i64(value: i64) -> Self {
        // Self variant
        Self(value)
    }

    /// Create from raw scaled value (alias for `from_i64`)
    #[must_use]
    pub const fn from_raw(value: i64) -> Self {
        // Self variant
        Self(value)
    }

    /// Get raw value
    #[must_use]
    pub const fn raw_value(self) -> i64 {
        self.0
    }

    /// Get inner value (public accessor for .0 field)
    #[must_use]
    pub const fn value(self) -> i64 {
        self.0
    }

    /// Create from floating point value
    #[must_use]
    pub fn from_f64(value: f64) -> Self {
        #[allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)]
        Self((value * PRICE_SCALE as f64) as i64)
    }

    /// Convert to floating point (for display)
    #[must_use]
    #[allow(clippy::cast_precision_loss)]
    pub fn to_f64(self) -> f64 {
        self.0 as f64 / PRICE_SCALE as f64
    }

    /// Convert to floating point (alias for `to_f64`)
    #[must_use]
    #[allow(clippy::cast_precision_loss)]
    pub fn as_f64(self) -> f64 {
        self.to_f64()
    }

    /// Convert to `f32` (for ML compatibility)
    #[must_use]
    #[allow(clippy::cast_precision_loss)]
    pub fn to_f32(self) -> f32 {
        self.0 as f32 / PRICE_SCALE as f32
    }

    /// Absolute value
    #[must_use]
    pub const fn abs(self) -> Self {
        Self(self.0.abs())
    }

    /// Square root
    #[must_use]
    #[allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)]
    pub fn sqrt(self) -> Self {
        let sqrt_val = ((self.0 as f64 / PRICE_SCALE as f64).sqrt() * PRICE_SCALE as f64) as i64;
        // Self variant
        Self(sqrt_val)
    }

    /// Convert to `Decimal` with proper precision
    ///
    /// # Returns
    /// A `Decimal` representation of this price with 6 decimal places of precision
    ///
    /// # Example
    /// ``
    /// use common::financial::IntegerPrice;
    /// use common::financial::Decimal;
    ///
    /// let price = IntegerPrice::from_f64(123.456_789);
    /// let decimal = price.to_decimal();
    /// // Should be close to 123.456_789
    /// ``
    #[must_use]
    pub fn to_decimal(self) -> Decimal {
        Decimal::new(self.0, 6)
    }

    /// Create IntegerPrice from `Decimal`
    #[must_use]
    #[allow(clippy::arithmetic_side_effects)]
    pub fn from_decimal(decimal: Decimal) -> Self {
        // Convert decimal to scaled integer representation
        let scaled = decimal * Decimal::new(PRICE_SCALE, 0);
        Self(scaled.mantissa().try_into().unwrap_or(0))
    }
}

impl Add for IntegerPrice {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        Self(self.0.saturating_add(other.0))
    }
}

impl std::ops::AddAssign for IntegerPrice {
    fn add_assign(&mut self, other: Self) {
        self.0 = self.0.saturating_add(other.0);
    }
}

impl Sub for IntegerPrice {
    type Output = Self;
    fn sub(self, other: Self) -> Self {
        Self(self.0.saturating_sub(other.0))
    }
}

impl Mul<i64> for IntegerPrice {
    type Output = Self;
    fn mul(self, rhs: i64) -> Self {
        Self(self.0.saturating_mul(rhs))
    }
}

impl Div<i64> for IntegerPrice {
    type Output = Self;
    fn div(self, rhs: i64) -> Self {
        if rhs == 0 {
            // Self variant
            Self(0)
        } else {
            Self(self.0.saturating_div(rhs))
        }
    }
}

/// Arithmetic operations with `Decimal` for proper financial calculations
impl Add<Decimal> for IntegerPrice {
    type Output = Decimal;
    fn add(self, rhs: Decimal) -> Decimal {
        self.to_decimal() + rhs
    }
}

impl Sub<Decimal> for IntegerPrice {
    type Output = Decimal;
    fn sub(self, rhs: Decimal) -> Decimal {
        self.to_decimal() - rhs
    }
}

impl Mul<Decimal> for IntegerPrice {
    type Output = Decimal;
    fn mul(self, rhs: Decimal) -> Decimal {
        self.to_decimal() * rhs
    }
}

impl Div<Decimal> for IntegerPrice {
    type Output = Decimal;
    fn div(self, rhs: Decimal) -> Decimal {
        if rhs == Decimal::ZERO {
            Decimal::ZERO
        } else {
            self.to_decimal() / rhs
        }
    }
}

/// Integer-based `quantity` type for exact share/contract tracking
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
/// `IntegerQuantity` component.
pub struct IntegerQuantity(pub i64);

impl IntegerQuantity {
    /// Zero `quantity` constant
    pub const ZERO: Self = Self(0);

    /// Create from `i64` value
    #[must_use]
    pub const fn from_i64(value: i64) -> Self {
        // Self variant
        Self(value)
    }

    /// Get raw value
    #[must_use]
    pub const fn raw_value(self) -> i64 {
        self.0
    }

    /// Get inner value (public accessor for .0 field)
    #[must_use]
    pub const fn value(self) -> i64 {
        self.0
    }

    /// Create from floating point value
    #[must_use]
    #[allow(clippy::cast_possible_truncation)] // Safe: scaled value intended to fit in i64 range
    #[allow(clippy::cast_precision_loss)] // Intentional: Financial scaling constant
    pub fn from_f64(value: f64) -> Self {
        Self((value * QUANTITY_SCALE as f64) as i64)
    }

    /// Convert to floating point (for display)
    #[must_use]
    #[allow(clippy::cast_precision_loss)] // Intentional: Financial precision conversion
    pub fn to_f64(self) -> f64 {
        self.0 as f64 / QUANTITY_SCALE as f64
    }

    /// Convert to `i64`
    #[must_use]
    pub const fn to_i64(self) -> i64 {
        self.0
    }

    /// Convert to `Decimal` with proper precision
    ///
    /// # Returns
    /// A `Decimal` representation of this quantity with 6 decimal places of precision
    ///
    /// # Example
    /// ``
    /// use common::financial::IntegerQuantity;
    /// use common::financial::Decimal;
    ///
    /// let quantity = IntegerQuantity::from_f64(123.456_789);
    /// let decimal = quantity.to_decimal();
    /// // Should be close to 123.456789
    /// ``
    #[must_use]
    pub fn to_decimal(self) -> Decimal {
        Decimal::new(self.0, 6)
    }

    /// Create IntegerQuantity from `Decimal`
    #[must_use]
    #[allow(clippy::arithmetic_side_effects)]
    pub fn from_decimal(decimal: Decimal) -> Self {
        // Convert decimal to scaled integer representation
        let scaled = decimal * Decimal::new(QUANTITY_SCALE, 0);
        Self(scaled.mantissa().try_into().unwrap_or(0))
    }
}

impl Add for IntegerQuantity {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        Self(self.0.saturating_add(other.0))
    }
}

impl Sub for IntegerQuantity {
    type Output = Self;
    fn sub(self, other: Self) -> Self {
        Self(self.0.saturating_sub(other.0))
    }
}

impl Mul<i64> for IntegerQuantity {
    type Output = Self;
    fn mul(self, rhs: i64) -> Self {
        Self(self.0.saturating_mul(rhs))
    }
}

impl Div<i64> for IntegerQuantity {
    type Output = Self;
    fn div(self, rhs: i64) -> Self {
        if rhs == 0 {
            // Self variant
            Self(0)
        } else {
            Self(self.0.saturating_div(rhs))
        }
    }
}

/// Arithmetic operations with `Decimal` for proper financial calculations
impl Add<Decimal> for IntegerQuantity {
    type Output = Decimal;
    fn add(self, rhs: Decimal) -> Decimal {
        self.to_decimal() + rhs
    }
}

impl Sub<Decimal> for IntegerQuantity {
    type Output = Decimal;
    fn sub(self, rhs: Decimal) -> Decimal {
        self.to_decimal() - rhs
    }
}

impl Mul<Decimal> for IntegerQuantity {
    type Output = Decimal;
    fn mul(self, rhs: Decimal) -> Decimal {
        self.to_decimal() * rhs
    }
}

impl Div<Decimal> for IntegerQuantity {
    type Output = Decimal;
    fn div(self, rhs: Decimal) -> Decimal {
        if rhs == Decimal::ZERO {
            Decimal::ZERO
        } else {
            self.to_decimal() / rhs
        }
    }
}

/// Integer-based money type for exact monetary calculations
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
/// `IntegerMoney` component.
pub struct IntegerMoney(pub i64);

impl Default for IntegerMoney {
    fn default() -> Self {
        Self::ZERO
    }
}

impl std::fmt::Display for IntegerMoney {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // Display as decimal with proper currency formatting
        let dollars = self.0 / 100;
        let cents = self.0 % 100;
        write!(f, "{}.{:02}", dollars, cents.abs())
    }
}

impl IntegerMoney {
    /// Zero money constant
    pub const ZERO: Self = Self(0);
    /// Create a zero amount
    #[must_use]
    pub const fn zero() -> Self {
        Self::ZERO
    }

    /// Create from `i64` value
    #[must_use]
    pub const fn from_i64(value: i64) -> Self {
        // Self variant
        Self(value)
    }

    /// Get raw value
    #[must_use]
    pub const fn raw_value(self) -> i64 {
        self.0
    }

    /// Get inner value (public accessor for .0 field)
    #[must_use]
    pub const fn value(self) -> i64 {
        self.0
    }

    /// Create from floating point value
    #[must_use]
    #[allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)] // Intentional: Financial scaling
    pub fn from_f64(value: f64) -> Self {
        Self((value * MONEY_SCALE as f64) as i64)
    }

    /// Convert to floating point (for display)
    #[allow(clippy::cast_precision_loss)] // Intentional: HFT display conversion
    #[must_use]
    pub fn to_f64(self) -> f64 {
        self.0 as f64 / MONEY_SCALE as f64
    }

    /// Convert to `Decimal` with proper precision
    ///
    /// # Returns
    /// A `Decimal` representation of this price with 6 decimal places of precision
    ///
    /// # Example
    /// ``
    ///
    /// let price = Price::from_f64(123.456_789).expect("Valid price");
    /// let decimal = price.to_decimal();
    /// assert_eq!(decimal.to_string(), "123.456_789");
    /// ``
    #[must_use]
    pub fn to_decimal(self) -> Decimal {
        Decimal::new(self.0, 6)
    }

    /// Convert to `IntegerPrice`
    #[must_use]
    pub const fn to_price(self) -> IntegerPrice {
        IntegerPrice::from_i64(self.0)
    }
}

impl Add for IntegerMoney {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        Self(self.0.saturating_add(other.0))
    }
}

impl Sub for IntegerMoney {
    type Output = Self;
    fn sub(self, other: Self) -> Self {
        Self(self.0.saturating_sub(other.0))
    }
}

impl Mul<i64> for IntegerMoney {
    type Output = Self;
    fn mul(self, rhs: i64) -> Self {
        Self(self.0.saturating_mul(rhs))
    }
}

impl Div<i64> for IntegerMoney {
    type Output = Self;
    fn div(self, rhs: i64) -> Self {
        if rhs == 0 {
            // Self variant
            Self(0)
        } else {
            Self(self.0.saturating_div(rhs))
        }
    }
}

/// Reverse arithmetic operations - `Decimal` with Integer types
impl Add<IntegerPrice> for Decimal {
    type Output = Decimal;
    fn add(self, rhs: IntegerPrice) -> Decimal {
        self + rhs.to_decimal()
    }
}

impl Sub<IntegerPrice> for Decimal {
    type Output = Decimal;
    fn sub(self, rhs: IntegerPrice) -> Decimal {
        self - rhs.to_decimal()
    }
}

impl Mul<IntegerPrice> for Decimal {
    type Output = Decimal;
    fn mul(self, rhs: IntegerPrice) -> Decimal {
        self * rhs.to_decimal()
    }
}

impl Div<IntegerPrice> for Decimal {
    type Output = Decimal;
    fn div(self, rhs: IntegerPrice) -> Decimal {
        if rhs.to_decimal() == Decimal::ZERO {
            Decimal::ZERO
        } else {
            self / rhs.to_decimal()
        }
    }
}

impl Add<IntegerQuantity> for Decimal {
    type Output = Decimal;
    fn add(self, rhs: IntegerQuantity) -> Decimal {
        self + rhs.to_decimal()
    }
}

impl Sub<IntegerQuantity> for Decimal {
    type Output = Decimal;
    fn sub(self, rhs: IntegerQuantity) -> Decimal {
        self - rhs.to_decimal()
    }
}

impl Mul<IntegerQuantity> for Decimal {
    type Output = Decimal;
    fn mul(self, rhs: IntegerQuantity) -> Decimal {
        self * rhs.to_decimal()
    }
}

impl Div<IntegerQuantity> for Decimal {
    type Output = Decimal;
    fn div(self, rhs: IntegerQuantity) -> Decimal {
        if rhs.to_decimal() == Decimal::ZERO {
            Decimal::ZERO
        } else {
            self / rhs.to_decimal()
        }
    }
}

/// Trait for `price` operations
pub trait PriceOperations {
    /// Add two prices together
    #[must_use]
    fn add_price(self, other: Self) -> Self;
    /// Subtract one `price` from another
    #[must_use]
    fn sub_price(self, other: Self) -> Self;
}

impl PriceOperations for IntegerPrice {
    fn add_price(self, other: Self) -> Self {
        self + other
    }

    fn sub_price(self, other: Self) -> Self {
        self - other
    }
}

/// Trait for money operations
pub trait MoneyOperations {
    /// Add two money amounts together
    #[must_use]
    fn add_money(self, other: Self) -> Self;
    /// Subtract one money amount from another
    #[must_use]
    fn sub_money(self, other: Self) -> Self;
}

impl MoneyOperations for IntegerMoney {
    fn add_money(self, other: Self) -> Self {
        self + other
    }

    fn sub_money(self, other: Self) -> Self {
        self - other
    }
}

/// Trait for `quantity` operations
pub trait QuantityOperations {
    /// Add two quantities together
    #[must_use]
    fn add_quantity(self, other: Self) -> Self;
    /// Subtract one `quantity` from another
    #[must_use]
    fn sub_quantity(self, other: Self) -> Self;
}

impl QuantityOperations for IntegerQuantity {
    fn add_quantity(self, other: Self) -> Self {
        self + other
    }

    fn sub_quantity(self, other: Self) -> Self {
        self - other
    }
}

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

    // ========================================================================
    // IntegerPrice Tests
    // ========================================================================

    #[test]
    fn test_integer_price_constants() {
        assert_eq!(IntegerPrice::ZERO.raw_value(), 0);
        assert_eq!(IntegerPrice::ONE.raw_value(), PRICE_SCALE);
    }

    #[test]
    fn test_integer_price_from_i64() {
        let price = IntegerPrice::from_i64(12345);
        assert_eq!(price.raw_value(), 12345);
        assert_eq!(price.value(), 12345);
    }

    #[test]
    fn test_integer_price_from_f64() {
        let price = IntegerPrice::from_f64(123.456_789);
        // Should scale by PRICE_SCALE (1,000,000)
        let expected = (123.456_789 * PRICE_SCALE as f64) as i64;
        assert_eq!(price.raw_value(), expected);
    }

    #[test]
    fn test_integer_price_to_f64() {
        let price = IntegerPrice::from_i64(PRICE_SCALE);
        assert!((price.to_f64() - 1.0).abs() < f64::EPSILON);
    }

    #[test]
    fn test_integer_price_as_f64() {
        let price = IntegerPrice::from_i64(PRICE_SCALE * 2);
        assert!((price.as_f64() - 2.0).abs() < f64::EPSILON);
    }

    #[test]
    fn test_integer_price_to_f32() {
        let price = IntegerPrice::from_i64(PRICE_SCALE);
        assert!((price.to_f32() - 1.0).abs() < f32::EPSILON);
    }

    #[test]
    fn test_integer_price_abs() {
        let negative_price = IntegerPrice::from_i64(-12345);
        let positive_price = negative_price.abs();
        assert_eq!(positive_price.raw_value(), 12345);

        let positive_price2 = IntegerPrice::from_i64(12345);
        assert_eq!(positive_price2.abs().raw_value(), 12345);
    }

    #[test]
    fn test_integer_price_sqrt() {
        let price = IntegerPrice::from_i64(PRICE_SCALE * 4); // 4.0
        let sqrt_price = price.sqrt();
        let expected_sqrt = 2.0;
        let actual_sqrt = sqrt_price.to_f64();
        assert!((actual_sqrt - expected_sqrt).abs() < 0.001);
    }

    #[test]
    fn test_integer_price_addition() {
        let price1 = IntegerPrice::from_i64(100);
        let price2 = IntegerPrice::from_i64(200);
        let result = price1 + price2;
        assert_eq!(result.raw_value(), 300);
    }

    #[test]
    fn test_integer_price_addition_saturating() {
        let max_price = IntegerPrice::from_i64(i64::MAX);
        let small_price = IntegerPrice::from_i64(1);
        let result = max_price + small_price;
        assert_eq!(result.raw_value(), i64::MAX); // Should saturate
    }

    #[test]
    fn test_integer_price_add_assign() {
        let mut price = IntegerPrice::from_i64(100);
        let other = IntegerPrice::from_i64(200);
        price += other;
        assert_eq!(price.raw_value(), 300);
    }

    #[test]
    fn test_integer_price_subtraction() {
        let price1 = IntegerPrice::from_i64(300);
        let price2 = IntegerPrice::from_i64(100);
        let result = price1 - price2;
        assert_eq!(result.raw_value(), 200);
    }

    #[test]
    fn test_integer_price_subtraction_saturating() {
        let min_price = IntegerPrice::from_i64(i64::MIN);
        let small_price = IntegerPrice::from_i64(1);
        let result = min_price - small_price;
        assert_eq!(result.raw_value(), i64::MIN); // Should saturate
    }

    #[test]
    fn test_integer_price_multiplication() {
        let price = IntegerPrice::from_i64(100);
        let result = price * 3;
        assert_eq!(result.raw_value(), 300);
    }

    #[test]
    fn test_integer_price_multiplication_saturating() {
        let large_price = IntegerPrice::from_i64(i64::MAX / 2 + 1);
        let result = large_price * 3;
        assert_eq!(result.raw_value(), i64::MAX); // Should saturate
    }

    #[test]
    fn test_integer_price_division() {
        let price = IntegerPrice::from_i64(300);
        let result = price / 3;
        assert_eq!(result.raw_value(), 100);
    }

    #[test]
    fn test_integer_price_division_by_zero() {
        let price = IntegerPrice::from_i64(300);
        let result = price / 0;
        assert_eq!(result.raw_value(), 0); // Should handle divide by zero gracefully
    }

    #[test]
    fn test_simple_price_alias() {
        let price: IntegerPrice = IntegerPrice::from_i64(12345);
        assert_eq!(price.raw_value(), 12345);
    }

    // ========================================================================
    // IntegerQuantity Tests
    // ========================================================================

    #[test]
    fn test_integer_quantity_constants() {
        assert_eq!(IntegerQuantity::ZERO.raw_value(), 0);
    }

    #[test]
    fn test_integer_quantity_from_i64() {
        let qty = IntegerQuantity::from_i64(54321);
        assert_eq!(qty.raw_value(), 54321);
        assert_eq!(qty.value(), 54321);
    }

    #[test]
    fn test_integer_quantity_from_f64() {
        let qty = IntegerQuantity::from_f64(123.456_789);
        let expected = (123.456_789 * QUANTITY_SCALE as f64) as i64;
        assert_eq!(qty.raw_value(), expected);
    }

    #[test]
    fn test_integer_quantity_to_f64() {
        let qty = IntegerQuantity::from_i64(QUANTITY_SCALE);
        assert!((qty.to_f64() - 1.0).abs() < f64::EPSILON);
    }

    #[test]
    fn test_integer_quantity_to_i64() {
        let qty = IntegerQuantity::from_i64(12345);
        assert_eq!(qty.to_i64(), 12345);
    }

    #[test]
    fn test_integer_quantity_addition() {
        let qty1 = IntegerQuantity::from_i64(100);
        let qty2 = IntegerQuantity::from_i64(200);
        let result = qty1 + qty2;
        assert_eq!(result.raw_value(), 300);
    }

    #[test]
    fn test_integer_quantity_subtraction() {
        let qty1 = IntegerQuantity::from_i64(300);
        let qty2 = IntegerQuantity::from_i64(100);
        let result = qty1 - qty2;
        assert_eq!(result.raw_value(), 200);
    }

    #[test]
    fn test_integer_quantity_multiplication() {
        let qty = IntegerQuantity::from_i64(100);
        let result = qty * 3;
        assert_eq!(result.raw_value(), 300);
    }

    #[test]
    fn test_integer_quantity_division() {
        let qty = IntegerQuantity::from_i64(300);
        let result = qty / 3;
        assert_eq!(result.raw_value(), 100);
    }

    #[test]
    fn test_integer_quantity_division_by_zero() {
        let qty = IntegerQuantity::from_i64(300);
        let result = qty / 0;
        assert_eq!(result.raw_value(), 0); // Should handle divide by zero gracefully
    }

    // ========================================================================
    // IntegerMoney Tests
    // ========================================================================

    #[test]
    fn test_integer_money_constants() {
        assert_eq!(IntegerMoney::ZERO.raw_value(), 0);
        assert_eq!(IntegerMoney::zero().raw_value(), 0);
    }

    #[test]
    fn test_integer_money_default() {
        let money = IntegerMoney::default();
        assert_eq!(money.raw_value(), 0);
    }

    #[test]
    fn test_integer_money_display() {
        let money = IntegerMoney::from_i64(12345);
        let display_str = format!("{}", money);
        assert_eq!(display_str, "123.45"); // cents formatting
    }

    #[test]
    fn test_integer_money_display_negative() {
        let money = IntegerMoney::from_i64(-12345);
        let display_str = format!("{}", money);
        assert_eq!(display_str, "-123.45");
    }

    #[test]
    fn test_integer_money_from_i64() {
        let money = IntegerMoney::from_i64(98765);
        assert_eq!(money.raw_value(), 98765);
        assert_eq!(money.value(), 98765);
    }

    #[test]
    fn test_integer_money_from_f64() {
        let money = IntegerMoney::from_f64(123.456_789);
        let expected = (123.456_789 * MONEY_SCALE as f64) as i64;
        assert_eq!(money.raw_value(), expected);
    }

    #[test]
    fn test_integer_money_to_f64() {
        let money = IntegerMoney::from_i64(MONEY_SCALE);
        assert!((money.to_f64() - 1.0).abs() < f64::EPSILON);
    }

    #[test]
    fn test_integer_money_to_decimal() {
        let money = IntegerMoney::from_i64(12345);
        let decimal = money.to_decimal();
        assert_eq!(decimal.scale(), 6);
        assert_eq!(decimal.mantissa(), 12345);
    }

    #[test]
    fn test_integer_money_to_price() {
        let money = IntegerMoney::from_i64(12345);
        let price = money.to_price();
        assert_eq!(price.raw_value(), 12345);
    }

    #[test]
    fn test_integer_money_addition() {
        let money1 = IntegerMoney::from_i64(100);
        let money2 = IntegerMoney::from_i64(200);
        let result = money1 + money2;
        assert_eq!(result.raw_value(), 300);
    }

    #[test]
    fn test_integer_money_subtraction() {
        let money1 = IntegerMoney::from_i64(300);
        let money2 = IntegerMoney::from_i64(100);
        let result = money1 - money2;
        assert_eq!(result.raw_value(), 200);
    }

    #[test]
    fn test_integer_money_multiplication() {
        let money = IntegerMoney::from_i64(100);
        let result = money * 3;
        assert_eq!(result.raw_value(), 300);
    }

    #[test]
    fn test_integer_money_division() {
        let money = IntegerMoney::from_i64(300);
        let result = money / 3;
        assert_eq!(result.raw_value(), 100);
    }

    #[test]
    fn test_integer_money_division_by_zero() {
        let money = IntegerMoney::from_i64(300);
        let result = money / 0;
        assert_eq!(result.raw_value(), 0); // Should handle divide by zero gracefully
    }

    // ========================================================================
    // Trait Tests
    // ========================================================================

    #[test]
    fn test_price_operations_trait() {
        let price1 = IntegerPrice::from_i64(100);
        let price2 = IntegerPrice::from_i64(200);

        let added = price1.add_price(price2);
        assert_eq!(added.raw_value(), 300);

        let subtracted = price2.sub_price(price1);
        assert_eq!(subtracted.raw_value(), 100);
    }

    #[test]
    fn test_money_operations_trait() {
        let money1 = IntegerMoney::from_i64(100);
        let money2 = IntegerMoney::from_i64(200);

        let added = money1.add_money(money2);
        assert_eq!(added.raw_value(), 300);

        let subtracted = money2.sub_money(money1);
        assert_eq!(subtracted.raw_value(), 100);
    }

    #[test]
    fn test_quantity_operations_trait() {
        let qty1 = IntegerQuantity::from_i64(100);
        let qty2 = IntegerQuantity::from_i64(200);

        let added = qty1.add_quantity(qty2);
        assert_eq!(added.raw_value(), 300);

        let subtracted = qty2.sub_quantity(qty1);
        assert_eq!(subtracted.raw_value(), 100);
    }

    // ========================================================================
    // Scaling Constants Tests
    // ========================================================================

    #[test]
    fn test_scaling_constants() {
        assert_eq!(PRICE_SCALE, 1_000_000);
        assert_eq!(QUANTITY_SCALE, 1_000_000);
        assert_eq!(MONEY_SCALE, 1_000_000);
    }

    // ========================================================================
    // Edge Case Tests
    // ========================================================================

    #[test]
    fn test_integer_price_edge_cases() {
        // Test zero
        let zero_price = IntegerPrice::from_f64(0.0);
        assert_eq!(zero_price.raw_value(), 0);

        // Test negative values
        let negative_price = IntegerPrice::from_f64(-123.456);
        assert!(negative_price.raw_value() < 0);

        // Test very small values
        let small_price = IntegerPrice::from_f64(0.000_001);
        assert_eq!(small_price.raw_value(), 1); // Should be 1 after scaling
    }

    #[test]
    fn test_integer_quantity_edge_cases() {
        // Test zero
        let zero_qty = IntegerQuantity::from_f64(0.0);
        assert_eq!(zero_qty.raw_value(), 0);

        // Test negative values
        let negative_qty = IntegerQuantity::from_f64(-123.456);
        assert!(negative_qty.raw_value() < 0);
    }

    #[test]
    fn test_integer_money_edge_cases() {
        // Test zero
        let zero_money = IntegerMoney::from_f64(0.0);
        assert_eq!(zero_money.raw_value(), 0);

        // Test negative values
        let negative_money = IntegerMoney::from_f64(-123.456);
        assert!(negative_money.raw_value() < 0);

        // Test display of small amounts
        let small_money = IntegerMoney::from_i64(5);
        assert_eq!(format!("{}", small_money), "0.05");
    }

    // ========================================================================
    // Precision Tests
    // ========================================================================

    #[test]
    fn test_round_trip_precision_price() {
        let original = 123.456_789;
        let price = IntegerPrice::from_f64(original);
        let converted_back = price.to_f64();
        let diff = (original - converted_back).abs();
        assert!(diff < 0.000_001, "Precision loss too high: {}", diff);
    }

    #[test]
    fn test_round_trip_precision_quantity() {
        let original = 987.654_321;
        let qty = IntegerQuantity::from_f64(original);
        let converted_back = qty.to_f64();
        let diff = (original - converted_back).abs();
        assert!(diff < 0.000001, "Precision loss too high: {}", diff);
    }

    #[test]
    fn test_round_trip_precision_money() {
        let original = 567.890_123;
        let money = IntegerMoney::from_f64(original);
        let converted_back = money.to_f64();
        let diff = (original - converted_back).abs();
        assert!(diff < 0.000001, "Precision loss too high: {}", diff);
    }

    // ========================================================================
    // Comparison Tests
    // ========================================================================

    #[test]
    fn test_integer_price_comparisons() {
        let price1 = IntegerPrice::from_i64(100);
        let price2 = IntegerPrice::from_i64(200);
        let price3 = IntegerPrice::from_i64(100);

        assert!(price1 < price2);
        assert!(price2 > price1);
        assert_eq!(price1, price3);
        assert_ne!(price1, price2);
        assert!(price1 <= price2);
        assert!(price1 <= price3);
        assert!(price2 >= price1);
        assert!(price3 >= price1);
    }

    #[test]
    fn test_integer_quantity_comparisons() {
        let qty1 = IntegerQuantity::from_i64(100);
        let qty2 = IntegerQuantity::from_i64(200);
        let qty3 = IntegerQuantity::from_i64(100);

        assert!(qty1 < qty2);
        assert!(qty2 > qty1);
        assert_eq!(qty1, qty3);
        assert_ne!(qty1, qty2);
    }

    #[test]
    fn test_integer_money_comparisons() {
        let money1 = IntegerMoney::from_i64(100);
        let money2 = IntegerMoney::from_i64(200);
        let money3 = IntegerMoney::from_i64(100);

        assert!(money1 < money2);
        assert!(money2 > money1);
        assert_eq!(money1, money3);
        assert_ne!(money1, money2);
    }

    // ========================================================================
    // Hash Tests
    // ========================================================================

    #[test]
    fn test_integer_price_hash() {
        use std::collections::HashMap;
        let mut map = HashMap::new();
        let price = IntegerPrice::from_i64(12345);
        map.insert(price, "test");
        assert_eq!(map.get(&price), Some(&"test"));
    }

    #[test]
    fn test_integer_quantity_hash() {
        use std::collections::HashMap;
        let mut map = HashMap::new();
        let qty = IntegerQuantity::from_i64(12345);
        map.insert(qty, "test");
        assert_eq!(map.get(&qty), Some(&"test"));
    }

    #[test]
    fn test_integer_money_hash() {
        use std::collections::HashMap;
        // use crate::operations; // Available if needed
        let mut map = HashMap::new();
        let money = IntegerMoney::from_i64(12345);
        map.insert(money, "test");
        assert_eq!(map.get(&money), Some(&"test"));
    }

    // ========================================================================
    // Serialization Tests (if serde feature is enabled)
    // ========================================================================

    #[cfg(feature = "serde")]
    #[test]
    fn test_integer_price_serialization() -> Result<(), Box<dyn std::error::Error>> {
        let price = IntegerPrice::from_i64(12345);
        let serialized = serde_json::to_string(&price)?;
        let deserialized: IntegerPrice = serde_json::from_str(&serialized)?;
        assert_eq!(price, deserialized);
        Ok(())
    }

    #[cfg(feature = "serde")]
    #[test]
    fn test_integer_quantity_serialization() -> Result<(), Box<dyn std::error::Error>> {
        let qty = IntegerQuantity::from_i64(54321);
        let serialized = serde_json::to_string(&qty)?;
        let deserialized: IntegerQuantity = serde_json::from_str(&serialized)?;
        assert_eq!(qty, deserialized);
        Ok(())
    }

    #[cfg(feature = "serde")]
    #[test]
    fn test_integer_money_serialization() -> Result<(), Box<dyn std::error::Error>> {
        let money = IntegerMoney::from_i64(98765);
        let serialized = serde_json::to_string(&money)?;
        let deserialized: IntegerMoney = serde_json::from_str(&serialized)?;
        assert_eq!(money, deserialized);
        Ok(())
    }
}
