use serde::{Deserialize, Serialize};

/// Related links for a manga.
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, PartialOrd, Serialize)]
pub struct MangaLinks {
    /// Amazon Product URL
    #[serde(rename = "amz")]
    amazon: Option<String>,
    /// AniList ID
    #[serde(rename = "al")]
    anilist: Option<String>,
    /// Anime-Planet slug
    #[serde(rename = "ap")]
    anime_planet: Option<String>,
    /// BookWalker URI
    #[serde(rename = "bw")]
    book_walker: Option<BookWalker>,
    /// CDJapan URL
    #[serde(rename = "cdj")]
    cd_japan: Option<String>,
    /// EbookJapan URL
    #[serde(rename = "ebj")]
    ebook_japan: Option<String>,
    /// Kitsu ID
    #[serde(rename = "kt")]
    kitsu: Option<String>,
    /// MangaUpdates ID
    #[serde(rename = "mu")]
    manga_updates: Option<MangaUpdates>,
    /// MyAnimeList ID
    #[serde(rename = "mal")]
    my_anime_list: Option<MyAnimeList>,
    /// NovelUpdates slug
    #[serde(rename = "nu")]
    novel_updates: Option<NovelUpdates>,
    /// Raw URL
    raw: Option<String>,
    /// Official English URL
    #[serde(rename = "engtl")]
    english_translation: Option<String>,
}

impl MangaLinks {
    pub fn amazon(&self) -> &Option<String> {
        &self.amazon
    }

    pub fn anilist(&self) -> &Option<String> {
        &self.anilist
    }

    pub fn anime_planet(&self) -> &Option<String> {
        &self.anime_planet
    }

    pub fn book_walker(&self) -> &Option<BookWalker> {
        &self.book_walker
    }

    pub fn cd_japan(&self) -> &Option<String> {
        &self.cd_japan
    }

    pub fn ebook_japan(&self) -> &Option<String> {
        &self.ebook_japan
    }

    pub fn kitsu(&self) -> &Option<String> {
        &self.kitsu
    }

    pub fn manga_updates(&self) -> &Option<MangaUpdates> {
        &self.manga_updates
    }

    pub fn my_anime_list(&self) -> &Option<MyAnimeList> {
        &self.my_anime_list
    }

    pub fn novel_updates(&self) -> &Option<NovelUpdates> {
        &self.novel_updates
    }

    pub fn raw(&self) -> &Option<String> {
        &self.anilist
    }

    pub fn english_translation(&self) -> &Option<String> {
        &self.english_translation
    }
}

/// BookWalker URI.
///
/// Example: "`series/91701`".
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, PartialOrd, Serialize)]
pub struct BookWalker(pub String);

impl std::fmt::Display for BookWalker {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.write_str(&*format!("https://bookwalker.jp/{}", self.0))
    }
}

/// MangaUpdates ID.
///
/// Example: "`132515`".
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, PartialOrd, Serialize)]
pub struct MangaUpdates(pub String);

impl std::fmt::Display for MangaUpdates {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.write_str(&*format!(
            "https://www.mangaupdates.com/series.html?id={}",
            self.0
        ))
    }
}

/// MyAnimeList ID.
///
/// Example: "`98436`".
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, PartialOrd, Serialize)]
pub struct MyAnimeList(pub String);

impl std::fmt::Display for MyAnimeList {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.write_str(&*format!("https://myanimelist.net/manga/{}", self.0))
    }
}

/// NovelUpdates slug.
///
/// Example: "`novel-updates`".
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, PartialOrd, Serialize)]
pub struct NovelUpdates(pub String);

impl std::fmt::Display for NovelUpdates {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.write_str(&*format!("https://www.novelupdates.com/series/{}/", self.0))
    }
}
