use std::{
    collections::HashMap,
    error::Error,
    fmt::{Debug, Display},
    ops::{Deref, DerefMut},
};
use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
#[cfg_attr(feature = "salvo", derive(salvo::prelude::ToSchema))]
#[derive(Debug, Default)]
pub(crate) struct OrderedHashMap<K, V>(pub(crate) HashMap<K, V>);
impl<K, V> Serialize for OrderedHashMap<K, V>
where
    K: Serialize + Ord,
    V: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut sorted_entries: Vec<_> = self.0.iter().collect();
        sorted_entries.sort_by_key(|&(k, _)| k);
        let mut map = serializer.serialize_map(Some(sorted_entries.len()))?;
        for (k, v) in sorted_entries {
            map.serialize_entry(k, v)?;
        }
        map.end()
    }
}
impl<'de, K, V> Deserialize<'de> for OrderedHashMap<K, V>
where
    K: Deserialize<'de> + Eq + std::hash::Hash,
    V: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let map = HashMap::deserialize(deserializer)?;
        Ok(OrderedHashMap(map))
    }
}
impl<K, V> Deref for OrderedHashMap<K, V> {
    type Target = HashMap<K, V>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl<K, V> DerefMut for OrderedHashMap<K, V> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum MaybeString {
    String(String),
    Str(&'static str),
    OptionString(Option<String>),
    OptionStr(Option<&'static str>),
    UnitTuple,
}
impl From<()> for MaybeString {
    fn from(_: ()) -> Self {
        MaybeString::UnitTuple
    }
}
impl From<String> for MaybeString {
    fn from(value: String) -> Self {
        MaybeString::String(value)
    }
}
impl From<&'static str> for MaybeString {
    fn from(value: &'static str) -> Self {
        MaybeString::Str(value)
    }
}
impl From<Option<String>> for MaybeString {
    fn from(value: Option<String>) -> Self {
        MaybeString::OptionString(value)
    }
}
impl From<Option<&'static str>> for MaybeString {
    fn from(value: Option<&'static str>) -> Self {
        MaybeString::OptionStr(value)
    }
}
impl MaybeString {
    pub fn option_string(self) -> Option<String> {
        match self {
            MaybeString::String(v) => Some(v),
            MaybeString::Str(v) => Some(v.to_owned()),
            MaybeString::OptionString(v) => v,
            MaybeString::OptionStr(v) => v.map(|v| v.to_owned()),
            MaybeString::UnitTuple => None,
        }
    }
    pub fn expect(self, msg: &str) -> String {
        match self {
            MaybeString::String(v) => v,
            MaybeString::Str(v) => v.to_owned(),
            MaybeString::OptionString(v) => v.expect(msg),
            MaybeString::OptionStr(v) => v.expect(msg).to_owned(),
            MaybeString::UnitTuple => panic!("{msg}"),
        }
    }
    pub fn unwrap_or(self, default: impl Into<String>) -> String {
        match self {
            MaybeString::String(v) => v,
            MaybeString::Str(v) => v.to_owned(),
            MaybeString::OptionString(v) => v.unwrap_or_else(|| default.into()),
            MaybeString::OptionStr(v) => v.map_or_else(|| default.into(), |v| v.to_owned()),
            MaybeString::UnitTuple => default.into(),
        }
    }
    pub fn unwrap_or_else(self, f: impl FnOnce() -> String) -> String {
        match self {
            MaybeString::String(v) => v,
            MaybeString::Str(v) => v.to_owned(),
            MaybeString::OptionString(v) => v.unwrap_or_else(f),
            MaybeString::OptionStr(v) => v.map_or_else(f, |v| v.to_owned()),
            MaybeString::UnitTuple => f(),
        }
    }
    pub fn unwrap_or_default(self) -> String {
        match self {
            MaybeString::String(v) => v,
            MaybeString::Str(v) => v.to_owned(),
            MaybeString::OptionString(v) => v.unwrap_or_default(),
            MaybeString::OptionStr(v) => v.map_or_else(Default::default, |v| v.to_owned()),
            MaybeString::UnitTuple => Default::default(),
        }
    }
}
impl From<MaybeString> for Option<String> {
    fn from(value: MaybeString) -> Self {
        value.option_string()
    }
}
#[derive(Debug)]
pub struct ErrWrapper<E: Display>(pub E);
impl<E: Debug + Display> Display for ErrWrapper<E> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self.0, f)
    }
}
impl<E: Debug + Display> Error for ErrWrapper<E> {}
pub trait IntoError: Debug + Display + Sized {
    fn into_error(self) -> ErrWrapper<Self> {
        ErrWrapper(self)
    }
}
impl<E: Debug + Display + Sized> IntoError for E {}
#[cfg(test)]
mod tests {
    use std::{collections::HashMap, error::Error};
    use super::{IntoError, OrderedHashMap};
    #[test]
    fn ordered_hash_map() {
        const S: &str = r#"{"k1":"v1","k2":"v2"}"#;
        let mut map = HashMap::new();
        map.insert("k2", "v2");
        map.insert("k1", "v1");
        let map1 = OrderedHashMap(map);
        assert_eq!(S, serde_json::to_string(&map1).unwrap());
        let map2: OrderedHashMap<&str, &str> = serde_json::from_str(S).unwrap();
        assert_eq!(S, serde_json::to_string(&map2).unwrap());
    }
    #[test]
    fn error_wrapper() {
        let e: super::ErrWrapper<i32> = 1.into_error();
        let d: &dyn Error = &e;
        assert_eq!("1", d.to_string())
    }
}