use ciborium::value::Value;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AlgorithmCurve {
    None = 0,

    P256 = 1,
    P384 = 2,
    P512 = 3,
    Ed25519 = 6,
    Ed448 = 7,
}

impl AlgorithmCurve {
    pub fn is_some(&self) -> bool {
        match self {
            Self::None => false,
            _ => true,
        }
    }

    pub fn is_valid_with(&self, alg: &Algorithm) -> bool {
        use AlgorithmCurve::*;

        match alg {
            Algorithm::None => true,
            Algorithm::ECDSA => matches!(self, None | P256 | P384 | P512),
            Algorithm::EDDSA => matches!(self, None | Ed25519 | Ed448),
        }
    }
}

impl Default for AlgorithmCurve {
    fn default() -> Self {
        Self::None
    }
}

impl From<Value> for AlgorithmCurve {
    fn from(v: Value) -> Self {
        match v {
            Value::Integer(i) => {
                let i: i128 = i.into();
                match i {
                    1 => Self::P256,
                    2 => Self::P384,
                    3 => Self::P512,
                    6 => Self::Ed25519,
                    7 => Self::Ed448,
                    _ => Self::None,
                }
            }
            _ => Self::None,
        }
    }
}

impl Into<Value> for AlgorithmCurve {
    fn into(self) -> Value {
        match self {
            Self::P256 => Value::from(1),
            Self::P384 => Value::from(2),
            Self::P512 => Value::from(3),
            Self::Ed25519 => Value::from(6),
            Self::Ed448 => Value::from(7),
            Self::None => Value::Null,
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Algorithm {
    None,

    ECDSA = -7,
    EDDSA = -8,
}

impl Algorithm {
    pub fn is_some(&self) -> bool {
        match self {
            Self::None => false,
            _ => true,
        }
    }
}

impl Default for Algorithm {
    fn default() -> Self {
        Algorithm::None
    }
}

impl From<Value> for Algorithm {
    fn from(v: Value) -> Self {
        match v {
            Value::Integer(i) => {
                let i: i128 = i.into();
                match i {
                    -7 => Self::ECDSA,
                    -8 => Self::EDDSA,
                    _ => Self::None,
                }
            }
            _ => Self::None,
        }
    }
}

impl Into<Option<Value>> for Algorithm {
    fn into(self) -> Option<Value> {
        match self {
            Self::ECDSA => Some(Value::from(-7)),
            Self::EDDSA => Some(Value::from(-8)),
            Self::None => None,
        }
    }
}
