use serde::{Deserialize, Serialize};

/// Representation of the "status" field in the response JSON body.
#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, PartialOrd, Serialize)]
#[serde(from = "&str")]
#[repr(u8)]
pub enum MangaDexResponseStatus {
    Ok = 0,
    #[serde(other)]
    Error = 1,
}

impl Default for MangaDexResponseStatus {
    fn default() -> Self {
        1u8.into()
    }
}

impl std::fmt::Display for MangaDexResponseStatus {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.write_str(match self {
            Self::Ok => "Ok",
            Self::Error => "Error",
        })
    }
}

impl From<u8> for MangaDexResponseStatus {
    fn from(value: u8) -> Self {
        match value {
            0 => Self::Ok,
            1 => Self::Error,
            _ => Self::Error,
        }
    }
}

impl From<u16> for MangaDexResponseStatus {
    fn from(value: u16) -> Self {
        match value {
            0 => Self::Ok,
            1 => Self::Error,
            _ => Self::Error,
        }
    }
}

impl From<u32> for MangaDexResponseStatus {
    fn from(value: u32) -> Self {
        match value {
            0 => Self::Ok,
            1 => Self::Error,
            _ => Self::Error,
        }
    }
}

impl From<u64> for MangaDexResponseStatus {
    fn from(value: u64) -> Self {
        match value {
            0 => Self::Ok,
            1 => Self::Error,
            _ => Self::Error,
        }
    }
}

impl From<&str> for MangaDexResponseStatus {
    fn from(value: &str) -> Self {
        match value.to_lowercase().as_str() {
            "ok" => Self::Ok,
            "error" => Self::Error,
            _ => Self::Error,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn mangadex_response_status_produces_error_from_default() {
        let mangadex_response_status = MangaDexResponseStatus::default();
        assert_eq!(mangadex_response_status, MangaDexResponseStatus::Error);
    }

    #[test]
    fn mangadex_response_status_produces_ok_from_0() {
        let mangadex_response_status = MangaDexResponseStatus::from(0u8);
        assert_eq!(mangadex_response_status, MangaDexResponseStatus::Ok);
    }

    #[test]
    fn mangadex_response_status_produces_error_from_ok_string() {
        let mangadex_response_status = MangaDexResponseStatus::from("OK");
        assert_eq!(mangadex_response_status, MangaDexResponseStatus::Ok);
    }
}
