use crate::types::Tag;
use serde::{Deserialize, Serialize};

#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, PartialOrd, Serialize)]
#[serde(from = "&str")]
#[repr(u8)]
pub enum TagCategory {
    Unknown = 0,
    Content = 1,
    Format = 2,
    Genre = 3,
    Theme = 4,
    Demographic = 5,
}

impl From<&str> for TagCategory {
    fn from(s: &str) -> Self {
        match s {
            "Content" => Self::Content,
            "Format" => Self::Format,
            "Genre" => Self::Genre,
            "Theme" => Self::Theme,
            "Demographic" => Self::Demographic,
            _ => Self::Unknown,
        }
    }
}

impl std::fmt::Display for TagCategory {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        let name = match self {
            Self::Unknown => "Unknown",
            Self::Content => "Content",
            Self::Format => "Format",
            Self::Genre => "Genre",
            Self::Theme => "Theme",
            Self::Demographic => "Demographic",
        };
        fmt.write_str(name)
    }
}

impl TagCategory {
    pub fn tags(&self) -> Vec<Tag> {
        match self {
            Self::Unknown => vec![Tag::Unknown],
            Self::Content => vec![Tag::Ecchi, Tag::Smut, Tag::Gore, Tag::SexualViolence],
            Self::Format => vec![
                Tag::_4Koma,
                Tag::AwardWinning,
                Tag::Doujinshi,
                Tag::Oneshot,
                Tag::LongStrip,
                Tag::Adaptation,
                Tag::Anthology,
                Tag::WebComic,
                Tag::FullColor,
                Tag::UserCreated,
                Tag::OfficialColored,
                Tag::FanColored,
            ],
            Self::Genre => vec![
                Tag::Action,
                Tag::Adventure,
                Tag::Comedy,
                Tag::Drama,
                Tag::Fantasy,
                Tag::Historical,
                Tag::Horror,
                Tag::Mecha,
                Tag::Medical,
                Tag::Mystery,
                Tag::Psychological,
                Tag::Romance,
                Tag::SciFi,
                Tag::ShoujoAi,
                Tag::ShounenAi,
                Tag::SliceOfLife,
                Tag::Sports,
                Tag::Tragedy,
                Tag::Yaoi,
                Tag::Yuri,
                Tag::Isekai,
                Tag::Crime,
                Tag::MagicalGirls,
                Tag::Philosophical,
                Tag::Superhero,
                Tag::Thriller,
                Tag::Wuxia,
            ],
            Self::Theme => vec![
                Tag::Cooking,
                Tag::Gyaru,
                Tag::Harem,
                Tag::MartialArts,
                Tag::Music,
                Tag::SchoolLife,
                Tag::Supernatural,
                Tag::VideoGames,
                Tag::Aliens,
                Tag::Animals,
                Tag::Crossdressing,
                Tag::Demons,
                Tag::Delinquents,
                Tag::Genderswap,
                Tag::Ghosts,
                Tag::MonsterGirls,
                Tag::Loli,
                Tag::Magic,
                Tag::Military,
                Tag::Monsters,
                Tag::Ninja,
                Tag::OfficeWorkers,
                Tag::Police,
                Tag::PostApocalyptic,
                Tag::Reincarnation,
                Tag::ReverseHarem,
                Tag::Samurai,
                Tag::Shota,
                Tag::Survival,
                Tag::TimeTravel,
                Tag::Vampires,
                Tag::TraditionalGames,
                Tag::VirtualReality,
                Tag::Zombies,
                Tag::Incest,
                Tag::Mafia,
                Tag::Villainess,
            ],
            TagCategory::Demographic => vec![],
        }
    }
}

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

    #[test]
    fn category_produces_content_from_string_content() {
        let category = TagCategory::from("Content");
        assert_eq!(category, TagCategory::Content);
    }

    #[test]
    fn category_produces_unknown_from_unrecognized_string() {
        let category = TagCategory::from("non-matching category");
        assert_eq!(category, TagCategory::Unknown);
    }
}
