use crate::constants::Q32_ONE;

/// Convert a floating-point value to Q32.32 fixed-point.
pub fn to_q32(value: f64) -> u64 {
    (value * Q32_ONE as f64) as u64
}

/// Convert a Q32.32 fixed-point value to floating-point.
pub fn from_q32(q32: u64) -> f64 {
    let integer_part = q32 >> 32;
    let fractional_part = q32 & 0xFFFF_FFFF;
    integer_part as f64 + (fractional_part as f64 / Q32_ONE as f64)
}

/// Convert a percentage (0.0 to 1.0) to Q32.32.
pub fn pct_to_q32(pct: f64) -> u64 {
    to_q32(pct)
}

/// Convert basis points to a Q32.32 spread factor.
/// Example: 5 bps -> to_q32(0.9995)
pub fn spread_bps_to_q32(bps: u16) -> u64 {
    to_q32(1.0 - (bps as f64) / 10_000.0)
}

/// Convert a Q32.32 spread factor to basis points.
/// Example: to_q32(0.9995) -> 5.0
pub fn spread_q32_to_bps(q32: u64) -> f64 {
    (1.0 - from_q32(q32)) * 10_000.0
}

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

    #[test]
    fn test_q32_roundtrip() {
        let original = 1.5;
        let q32 = to_q32(original);
        let back = from_q32(q32);
        assert!((back - original).abs() < 1e-9);
    }

    #[test]
    fn test_q32_one() {
        assert_eq!(to_q32(1.0), Q32_ONE);
        assert!((from_q32(Q32_ONE) - 1.0).abs() < 1e-9);
    }

    #[test]
    fn test_spread_bps_roundtrip() {
        let bps: u16 = 5;
        let q32 = spread_bps_to_q32(bps);
        let back = spread_q32_to_bps(q32);
        assert!((back - 5.0).abs() < 0.01);
    }
}
