use crate::types::{HentaiMode, Language};

/// MangaDex cookies that control various features such as restricting language results.
#[derive(Clone, Debug, Hash, PartialEq, PartialOrd)]
pub enum MangaDexCookie {
    /// Only return chapters that match the languages.
    FilterChapterLanguages(Vec<Language>),
    /// Toggle showing hentai content.
    HentaiToggle(HentaiMode),
    /// Long-term session token.
    #[allow(dead_code)]
    RememberMeToken(String),
    /// MangaDex session; UUID v4.
    #[allow(dead_code)]
    Session(String),
}

impl std::fmt::Display for MangaDexCookie {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        let value = match self {
            Self::FilterChapterLanguages(languages) => format!(
                "{key}={lang_ids}",
                key = self.key(),
                lang_ids = languages
                    .iter()
                    .map(|lang| (*lang as u8).to_string())
                    .collect::<Vec<String>>()
                    .join(",")
            ),
            Self::HentaiToggle(mode) => format!(
                "{key}={hentai_mode}",
                key = self.key(),
                hentai_mode = (*mode as u8)
            ),
            Self::RememberMeToken(token) => {
                format!("{key}={token}", key = self.key(), token = token)
            }
            Self::Session(id) => format!("{key}={id}", key = self.key(), id = id),
        };

        fmt.write_str(&*value)
    }
}

impl MangaDexCookie {
    pub fn key(&self) -> &str {
        match &self {
            Self::FilterChapterLanguages(_) => "mangadex_filter_langs",
            Self::HentaiToggle(_) => "mangadex_h_toggle",
            Self::RememberMeToken(_) => "mangadex_rememberme_token",
            Self::Session(_) => "mangadex_session",
        }
    }
}

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

    #[test]
    fn filter_chapter_languages_cookie_produces_correct_key() {
        let filter_chapter_languages_cookie =
            MangaDexCookie::FilterChapterLanguages(vec![Language::English, Language::Japanese]);

        assert_eq!(
            filter_chapter_languages_cookie.key(),
            "mangadex_filter_langs"
        )
    }

    #[test]
    fn hentai_toggle_cookie_produces_correct_key() {
        let hentai_toggle_cookie = MangaDexCookie::HentaiToggle(HentaiMode::ShowOnly);

        assert_eq!(hentai_toggle_cookie.key(), "mangadex_h_toggle")
    }

    #[test]
    fn rememberme_cookie_produces_correct_key() {
        let token = "d2eda9792dd7d3baf6ee6500b327c379c36526b5282ddced8ccb8da062c0776f".to_string();
        let rememberme_token_cookie = MangaDexCookie::RememberMeToken(token);

        assert_eq!(rememberme_token_cookie.key(), "mangadex_rememberme_token");
    }

    #[test]
    fn session_cookie_produces_correct_key() {
        let session_id = "4570c0e0-03b6-426a-8ef0-24fcb6412623".to_string();
        let session_cookie = MangaDexCookie::Session(session_id);

        assert_eq!(session_cookie.key(), "mangadex_session");
    }

    #[test]
    fn filter_chapter_languages_cookie_produces_correct_string() {
        let filter_chapter_languages_cookie =
            MangaDexCookie::FilterChapterLanguages(vec![Language::English, Language::Japanese]);

        assert_eq!(
            filter_chapter_languages_cookie.to_string(),
            "mangadex_filter_langs=1,2"
        )
    }

    #[test]
    fn hentai_toggle_cookie_produces_correct_string() {
        let hentai_toggle_cookie = MangaDexCookie::HentaiToggle(HentaiMode::ShowOnly);

        assert_eq!(hentai_toggle_cookie.to_string(), "mangadex_h_toggle=2")
    }

    #[test]
    fn rememberme_cookie_produces_correct_string() {
        let token = "d2eda9792dd7d3baf6ee6500b327c379c36526b5282ddced8ccb8da062c0776f".to_string();
        let rememberme_token_cookie = MangaDexCookie::RememberMeToken(token.clone());

        assert_eq!(
            rememberme_token_cookie.to_string(),
            format!("mangadex_rememberme_token={}", token)
        );
    }

    #[test]
    fn session_cookie_produces_correct_string() {
        let session_id = "4570c0e0-03b6-426a-8ef0-24fcb6412623".to_string();
        let session_cookie = MangaDexCookie::Session(session_id.clone());

        assert_eq!(
            session_cookie.to_string(),
            format!("mangadex_session={}", session_id)
        );
    }
}
