use serde::{Deserialize, Serialize};

#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, PartialOrd, Serialize)]
#[serde(from = "u8")]
#[repr(u8)]
pub enum FollowStatus {
    Reading = 1,
    Completed = 2,
    OnHold = 3,
    PlanToRead = 4,
    Dropped = 5,
    ReReading = 6,
    #[serde(other)]
    RemoveFiltering = 0,
}

impl Default for FollowStatus {
    fn default() -> Self {
        0u8.into()
    }
}

impl std::fmt::Display for FollowStatus {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.write_str(match self {
            Self::Reading => "Reading",
            Self::Completed => "Completed",
            Self::OnHold => "On hold",
            Self::PlanToRead => "Plan to read",
            Self::Dropped => "Dropped",
            Self::ReReading => "Re-reading",
            Self::RemoveFiltering => "Remove filtering",
        })
    }
}

impl From<u8> for FollowStatus {
    fn from(value: u8) -> Self {
        match value {
            1 => Self::Reading,
            2 => Self::Completed,
            3 => Self::OnHold,
            4 => Self::PlanToRead,
            5 => Self::Dropped,
            6 => Self::ReReading,
            _ => Self::RemoveFiltering,
        }
    }
}

impl From<u16> for FollowStatus {
    fn from(value: u16) -> Self {
        match value {
            1 => Self::Reading,
            2 => Self::Completed,
            3 => Self::OnHold,
            4 => Self::PlanToRead,
            5 => Self::Dropped,
            6 => Self::ReReading,
            _ => Self::RemoveFiltering,
        }
    }
}

impl From<u32> for FollowStatus {
    fn from(value: u32) -> Self {
        match value {
            1 => Self::Reading,
            2 => Self::Completed,
            3 => Self::OnHold,
            4 => Self::PlanToRead,
            5 => Self::Dropped,
            6 => Self::ReReading,
            _ => Self::RemoveFiltering,
        }
    }
}

impl From<u64> for FollowStatus {
    fn from(value: u64) -> Self {
        match value {
            1 => Self::Reading,
            2 => Self::Completed,
            3 => Self::OnHold,
            4 => Self::PlanToRead,
            5 => Self::Dropped,
            6 => Self::ReReading,
            _ => Self::RemoveFiltering,
        }
    }
}

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

    #[test]
    fn follow_status_produces_remove_filtering_from_default() {
        let follow_status = FollowStatus::default();
        assert_eq!(follow_status, FollowStatus::RemoveFiltering);
    }

    #[test]
    fn follow_status_produces_remove_filtering_from_0() {
        let follow_status = FollowStatus::from(0u8);
        assert_eq!(follow_status, FollowStatus::RemoveFiltering);
    }

    #[test]
    fn follow_status_produces_reading_from_1() {
        let follow_status = FollowStatus::from(1u8);
        assert_eq!(follow_status, FollowStatus::Reading);
    }
}
