use rust_decimal::Decimal;

pub mod opt {
    use rust_decimal::Decimal;

    #[allow(non_camel_case_types)]
    pub struct with_precision<const PRECISION: u32>;

    impl<const PRECISION: u32> with_precision<PRECISION> {
        pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            struct Visitor<const PRECISION: u32>;

            impl<'de, const PRECISION: u32> serde::de::Visitor<'de> for Visitor<PRECISION> {
                type Value = Option<Decimal>;

                fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    formatter.write_str("an optional decimal number in german format")
                }

                fn visit_none<E>(self) -> Result<Self::Value, E>
                where
                    E: serde::de::Error,
                {
                    Ok(None)
                }

                fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
                where
                    D: serde::Deserializer<'de>,
                {
                    super::with_precision::<PRECISION>::deserialize(deserializer).map(Some)
                }
            }

            deserializer.deserialize_option(Visitor::<PRECISION>)
        }
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct Visitor;

        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Option<Decimal>;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("an optional decimal number in german format")
            }

            fn visit_none<E>(self) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(None)
            }

            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
            where
                D: serde::Deserializer<'de>,
            {
                super::deserialize(deserializer).map(Some)
            }
        }

        deserializer.deserialize_option(Visitor)
    }
}

#[allow(non_camel_case_types)]
pub struct with_precision<const PRECISION: u32>;

impl<const PRECISION: u32> with_precision<PRECISION> {
    pub fn deserialize<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct Visitor<const PRECISION: u32>;

        impl<'de, const PRECISION: u32> serde::de::Visitor<'de> for Visitor<PRECISION> {
            type Value = Decimal;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("a decimal number in german format")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                let mut amount = crate::parse(v).map_err(E::custom)?;
                amount.rescale(PRECISION);
                Ok(amount)
            }
        }

        deserializer.deserialize_str(Visitor::<PRECISION>)
    }
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
where
    D: serde::Deserializer<'de>,
{
    struct Visitor;

    impl<'de> serde::de::Visitor<'de> for Visitor {
        type Value = Decimal;

        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
            formatter.write_str("a decimal number in german format")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            crate::parse(v).map_err(E::custom)
        }
    }

    deserializer.deserialize_str(Visitor)
}