use crate::datafile::variable::VariableType;

#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq, Clone))]
pub struct Variable {
    pub key: String,
    pub kind: String,
    pub value: JsonValue,
}

#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq, Clone))]
pub enum JsonValue {
    Boolean(bool),
    Number(f64),
    String(String),
    Json(String),
    Js(String),
    Css(String),
}

impl JsonValue {
    pub(crate) fn from_internal(var_type: &VariableType, value: &serde_json::Value) -> Self {
        match var_type {
            VariableType::Boolean => Self::Boolean(value.as_bool().unwrap_or(false)),
            VariableType::Number => Self::Number(value.as_f64().unwrap_or(f64::NAN)),
            VariableType::Json => Self::Json(value.as_str().unwrap_or("").to_owned()),
            VariableType::Js => Self::Js(value.as_str().unwrap_or("").to_owned()),
            VariableType::Css => Self::Css(value.as_str().unwrap_or("").to_owned()),
            _ => Self::String(value.as_str().unwrap_or("").to_owned()),
        }
    }
}

impl JsonValue {
    pub fn as_number(&self) -> Option<f64> {
        match self {
            Self::Number(n) => Some(*n),
            _ => None,
        }
    }

    pub fn as_bool(&self) -> Option<bool> {
        match self {
            Self::Boolean(b) => Some(*b),
            _ => None,
        }
    }

    pub fn as_str(&self) -> Option<&str> {
        match self {
            Self::String(s) | Self::Json(s) | Self::Js(s) | Self::Css(s) => Some(s.as_str()),
            _ => None,
        }
    }
}
