use crate::*;

/// Used by the [`num`] macro to convert integer literals to `Self`.
pub trait FromIntLiteral: Sized {
    /// The minimum integer literal that can be converted to `Self` without loosing precision.
    ///
    /// For an approximate minumum use `Self::MIN_APPROX_LITERAL`.
    ///
    /// An example for the difference between precise and approximate,
    /// is `f32` which can represent numbers up to `3.4028235 × 10³⁸`,
    /// but looses integer precision after `16_777_216`.
    const MIN_LITERAL: i128;
    /// The maximum integer literal that can be converted to `Self` without loosing precision.
    ///
    /// For an approximate maximum use `Self::MAX_APPROX_LITERAL`.
    ///
    /// An example for the difference between precise and approximate,
    /// is `f32` which can represent numbers up to `3.4028235 × 10³⁸`,
    /// but looses integer precision after `16_777_216`.
    const MAX_LITERAL: i128;
    /// The minimum integer literal that can be approximately converted to `Self`.
    ///
    /// This is set to `Self::MIN_LITERAL` on default.
    ///
    /// An example for the difference between precise and approximate,
    /// is `f32` which can represent numbers up to `3.4028235 × 10³⁸`,
    /// but looses integer precision after `16_777_216`.
    const MIN_APPROX_LITERAL: i128 = Self::MIN_LITERAL;

    /// The maximum integer literal that can be approximately converted to `Self`.
    ///
    /// This is set to `Self::MAX_LITERAL` on default.
    ///
    /// An example for the difference between precise and approximate,
    /// is `f32` which can represent numbers up to `3.4028235 × 10³⁸`,
    /// but looses integer precision after `16_777_216`.
    const MAX_APPROX_LITERAL: i128 = Self::MAX_LITERAL;

    /// Used by the [`num`] macro to convert integer literals to `Self`.
    ///
    /// Is unsafe because the caller must ensure that the value is between `Self::MIN_LITERAL` and `Self::MAX_LITERAL`.
    /// The fn is still expected to not cause undefined behavior if the value is out of range,
    /// because the fn is only unsafe to prevent it from being called manually.
    unsafe fn from_int_literal(value: i128) -> Self;

    /// Used by the [`num_approx`] macro to convert integer literals to `Self`.
    ///
    /// Is unsafe because the caller must ensure that the value is between `Self::MIN_APPROX_LITERAL` and `Self::MAX_APPROX_LITERAL`.
    /// The fn is still expected to not cause undefined behavior if the value is out of range,
    /// because the fn is only unsafe to prevent it from being called manually.
    unsafe fn approx_from_int_literal(value: i128) -> Self;
}

/// Used by the [`num`] macro to convert float literals to `Self`.
pub trait FromFloatLiteral: FromIntLiteral {
    /// Used by the [`num`] macro to convert float literals to `Self`.
    ///
    /// Is unsafe because the caller must ensure that the value is between `Self::MIN_LITERAL` and `Self::MAX_LITERAL`.
    unsafe fn from_float_literal(value: f64) -> Self;

    /// Used by the [`num_approx`] macro to convert float literals to `Self`.
    ///
    /// Is unsafe because the caller must ensure that the value is between `Self::MIN_APPROX_LITERAL` and `Self::MAX_APPROX_LITERAL`.
    unsafe fn approx_from_float_literal(value: f64) -> Self;

    fn pi() -> Self {
        internal_num!(3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949128831426076896280457)
    }
}

macro_rules! int_impl {
    ($ty:ident) => {
        impl FromIntLiteral for $ty {
            const MIN_LITERAL: i128 = $ty::MIN as i128;
            const MAX_LITERAL: i128 = $ty::MAX as i128;

            unsafe fn from_int_literal(value: i128) -> Self {
                value as Self
            }

            unsafe fn approx_from_int_literal(value: i128) -> Self {
                value as Self
            }
        }
    };
}
int_impl!(u8);
int_impl!(u16);
int_impl!(u32);
int_impl!(u64);
int_impl!(usize);
int_impl!(i8);
int_impl!(i16);
int_impl!(i32);
int_impl!(i64);
int_impl!(i128);
int_impl!(isize);

impl FromIntLiteral for u128 {
    const MIN_LITERAL: i128 = 0;
    const MAX_LITERAL: i128 = i128::MAX;

    unsafe fn from_int_literal(value: i128) -> Self {
        value as Self
    }

    unsafe fn approx_from_int_literal(value: i128) -> Self {
        value as Self
    }
}

impl FromIntLiteral for f32 {
    const MIN_LITERAL: i128 = 0;
    const MAX_LITERAL: i128 = 16_777_216; // 2^24
    const MIN_APPROX_LITERAL: i128 = 0;
    const MAX_APPROX_LITERAL: i128 = Self::MAX as i128;

    unsafe fn from_int_literal(value: i128) -> Self {
        value as Self
    }

    unsafe fn approx_from_int_literal(value: i128) -> Self {
        value as Self
    }
}

impl FromIntLiteral for f64 {
    const MIN_LITERAL: i128 = 0;
    const MAX_LITERAL: i128 = 9_007_199_254_740_992; // 2^53
    const MIN_APPROX_LITERAL: i128 = 0;
    const MAX_APPROX_LITERAL: i128 = i128::MAX; // f64 can represent all u128 values

    unsafe fn from_int_literal(value: i128) -> Self {
        value as Self
    }

    unsafe fn approx_from_int_literal(value: i128) -> Self {
        value as Self
    }
}

impl FromFloatLiteral for f32 {
    unsafe fn from_float_literal(value: f64) -> Self {
        value as Self
    }

    unsafe fn approx_from_float_literal(value: f64) -> Self {
        value as Self
    }
}

impl FromFloatLiteral for f64 {
    unsafe fn from_float_literal(value: f64) -> Self {
        value
    }

    unsafe fn approx_from_float_literal(value: f64) -> Self {
        value
    }
}
