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

#[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>,
}

impl NodeData {
    #[inline]
    pub fn new(svc: Option<&str>, online: bool, info: Option<NodeInfo>) -> Self {
        Self {
            svc: svc.map(ToOwned::to_owned),
            online: Arc::new(atomic::AtomicBool::new(online)),
            info,
        }
    }
    #[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 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);
    }
}

#[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,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum IdOrList<'a> {
    Single(&'a str),
    Multi(Vec<&'a str>),
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum IdOrListOwned {
    Single(String),
    Multi(Vec<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(Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum HostPath {
    Single(String),
    Multiple(Vec<String>),
}

impl Default for HostPath {
    #[inline]
    fn default() -> Self {
        HostPath::Multiple(Vec::new())
    }
}

impl HostPath {
    pub fn iter(&self) -> HostPathIter {
        HostPathIter {
            path: self,
            curr: 0,
        }
    }
    pub fn shuffle(&mut self) {
        if let HostPath::Multiple(ref mut v) = self {
            v.shuffle(&mut thread_rng());
        }
    }
}

pub struct HostPathIter<'a> {
    path: &'a HostPath,
    curr: usize,
}

impl<'a> Iterator for HostPathIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        let res = match self.path {
            HostPath::Single(v) => {
                if self.curr == 0 {
                    Some(v.as_str())
                } else {
                    None
                }
            }
            HostPath::Multiple(v) => v.get(self.curr).map(String::as_str),
        };
        self.curr += 1;
        res
    }
}
