use crate::{error::ConvertError, value::number::Number};
pub trait ToNumber<I, F>: Sized {
    type Err;
    fn to_number(self) -> Result<Number<I, F>, Self::Err>;
}
pub enum IntegerConverter {}
pub enum FloatConverter {}
pub trait Converter<I, F> {
    type Err;
    fn convert<N: Converting<I, F>>(n: N) -> Result<Number<I, F>, Self::Err>;
}
impl<I, F> Converter<I, F> for IntegerConverter
where
    I: num::FromPrimitive,
    F: num::FromPrimitive,
{
    type Err = crate::Error;
    fn convert<N: Converting<I, F>>(n: N) -> Result<Number<I, F>, Self::Err> {
        Ok(n.integer().map(Number::Integer).ok_or(ConvertError::InvalidIntegerConvert)?)
    }
}
impl<I, F> Converter<I, F> for FloatConverter
where
    I: num::FromPrimitive,
    F: num::FromPrimitive,
{
    type Err = crate::Error;
    fn convert<N: Converting<I, F>>(n: N) -> Result<Number<I, F>, Self::Err> {
        Ok(n.float().map(Number::Float).ok_or(ConvertError::InvalidFloatConvert)?)
    }
}
pub trait Converting<I, F>: Sized {
    type Converter: Converter<I, F>;
    fn integer(self) -> Option<I> {
        None
    }
    fn float(self) -> Option<F> {
        None
    }
    fn converting(self) -> Result<Number<I, F>, <Self::Converter as Converter<I, F>>::Err> {
        Self::Converter::convert(self)
    }
}
impl<N, I, F> ToNumber<I, F> for N
where
    N: Converting<I, F>,
    I: num::FromPrimitive,
    F: num::FromPrimitive,
{
    type Err = <<N as Converting<I, F>>::Converter as Converter<I, F>>::Err;
    fn to_number(self) -> Result<Number<I, F>, Self::Err> {
        self.converting()
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for u8 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_u8(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for u16 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_u16(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for u32 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_u32(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for u64 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_u64(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for u128 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_u128(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for i8 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_i8(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for i16 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_i16(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for i32 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_i32(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for i64 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_i64(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for i128 {
    type Converter = IntegerConverter;
    fn integer(self) -> Option<I> {
        I::from_i128(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for f32 {
    type Converter = FloatConverter;
    fn float(self) -> Option<F> {
        F::from_f32(self)
    }
}
impl<I: num::FromPrimitive, F: num::FromPrimitive> Converting<I, F> for f64 {
    type Converter = FloatConverter;
    fn float(self) -> Option<F> {
        F::from_f64(self)
    }
}