use crate::events::NodeInfo;
use crate::value::Value;
use crate::OID;
use rand::seq::SliceRandom;
use rand::thread_rng;
use serde::{Deserialize, Deserializer, Serialize};
use std::sync::atomic;
use std::sync::Arc;
use std::time::Duration;
use uuid::Uuid;

pub fn deserialize_uuid<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
where
    D: Deserializer<'de>,
{
    let val: Value = Deserialize::deserialize(deserializer)?;
    Uuid::deserialize(val).map_err(serde::de::Error::custom)
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct NodeData {
    svc: Option<String>,
    #[serde(
        deserialize_with = "crate::tools::deserialize_arc_atomic_bool",
        serialize_with = "crate::tools::serialize_atomic_bool"
    )]
    online: Arc<atomic::AtomicBool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    info: Option<NodeInfo>,
    #[serde(
        default,
        serialize_with = "crate::tools::serialize_opt_duration_as_f64",
        deserialize_with = "crate::tools::de_opt_float_as_duration"
    )]
    timeout: Option<Duration>,
}

impl NodeData {
    #[inline]
    pub fn new(
        svc: Option<&str>,
        online: bool,
        info: Option<NodeInfo>,
        timeout: Option<Duration>,
    ) -> Self {
        Self {
            svc: svc.map(ToOwned::to_owned),
            online: Arc::new(atomic::AtomicBool::new(online)),
            info,
            timeout,
        }
    }
    #[inline]
    pub fn svc(&self) -> Option<&str> {
        self.svc.as_deref()
    }
    #[inline]
    pub fn online(&self) -> bool {
        self.online.load(atomic::Ordering::SeqCst)
    }
    #[inline]
    pub fn online_beacon(&self) -> Arc<atomic::AtomicBool> {
        self.online.clone()
    }
    #[inline]
    pub fn info(&self) -> Option<&NodeInfo> {
        self.info.as_ref()
    }
    #[inline]
    pub fn timeout(&self) -> Option<Duration> {
        self.timeout
    }
    #[inline]
    pub fn set_online(&self, online: bool) {
        self.online.store(online, atomic::Ordering::SeqCst);
    }
    #[inline]
    pub fn update_info(&mut self, info: NodeInfo) {
        self.info.replace(info);
    }
    #[inline]
    pub fn update_timeout(&mut self, timeout: Option<Duration>) {
        self.timeout = timeout;
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParamsId<'a> {
    #[serde(borrow)]
    pub i: &'a str,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParamsIdOwned {
    pub i: String,
}

pub type IdOrList<'a> = ValueOrList<&'a str>;

pub type IdOrListOwned = ValueOrList<String>;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParamsIdOrList<'a> {
    #[serde(borrow)]
    pub i: IdOrList<'a>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParamsIdOrListOwned {
    pub i: IdOrListOwned,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParamsIdList<'a> {
    #[serde(borrow)]
    pub i: Vec<&'a str>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ParamsIdListOwned {
    pub i: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParamsOID {
    pub i: OID,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParamsUuid {
    pub u: Uuid,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParamsUuidAny {
    #[serde(deserialize_with = "deserialize_uuid")]
    pub u: Uuid,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum ValueOrList<T>
where
    T: Send + Sync + Clone,
{
    Single(T),
    Multiple(Vec<T>),
}

impl<T> Default for ValueOrList<T>
where
    T: Send + Sync + Clone,
{
    #[inline]
    fn default() -> Self {
        ValueOrList::Multiple(Vec::new())
    }
}

impl<T> ValueOrList<T>
where
    T: Send + Sync + Clone + PartialEq,
{
    pub fn is_empty(&self) -> bool {
        match self {
            ValueOrList::Single(_) => false,
            ValueOrList::Multiple(v) => v.is_empty(),
        }
    }
    pub fn len(&self) -> usize {
        match self {
            ValueOrList::Single(_) => 1,
            ValueOrList::Multiple(v) => v.len(),
        }
    }
    pub fn shuffle(&mut self) {
        if let ValueOrList::Multiple(ref mut v) = self {
            v.shuffle(&mut thread_rng());
        }
    }
    #[inline]
    pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
        self.into_iter()
    }
    pub fn to_vec(&self) -> Vec<T> {
        match self {
            ValueOrList::Single(v) => vec![v.clone()],
            ValueOrList::Multiple(v) => v.clone(),
        }
    }
    pub fn into_vec(self) -> Vec<T> {
        match self {
            ValueOrList::Single(v) => vec![v],
            ValueOrList::Multiple(v) => v,
        }
    }
    pub fn contains(&self, value: &T) -> bool {
        match self {
            ValueOrList::Single(v) => v == value,
            ValueOrList::Multiple(v) => v.contains(value),
        }
    }
}

impl<T: Send + Sync + Clone + 'static> IntoIterator for ValueOrList<T> {
    type Item = T;
    type IntoIter = Box<dyn Iterator<Item = Self::Item> + Send + Sync + 'static>;

    fn into_iter(self) -> Self::IntoIter {
        match self {
            ValueOrList::Single(s) => Box::new(SingleIter(Some(s))),
            ValueOrList::Multiple(vals) => Box::new(vals.into_iter()),
        }
    }
}

impl<'a, T: Send + Sync + Clone> IntoIterator for &'a ValueOrList<T> {
    type Item = &'a T;
    type IntoIter = Box<dyn Iterator<Item = Self::Item> + Send + Sync + 'a>;

    fn into_iter(self) -> Self::IntoIter {
        match self {
            ValueOrList::Single(s) => Box::new(SingleIter(Some(s))),
            ValueOrList::Multiple(vals) => Box::new(vals.iter()),
        }
    }
}

struct SingleIter<T>(Option<T>);

impl<T> Iterator for SingleIter<T> {
    type Item = T;
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.take()
    }
}
