use std::collections::HashMap;

use serde::Deserialize;

use crate::types::{MangaDexResponseStatus, MangaId, StatusCode};
use crate::v2::responses::partials::ChaptersDataPartial;
use crate::v2::responses::{ErrorResponse, ResponseBody, ResponseType};

#[derive(Debug, Deserialize, Clone, PartialEq)]
#[serde(untagged)]
pub enum UserFollowedUpdatesResponseType {
    Ok(UserFollowedUpdatesResponse),
    Err(ErrorResponse),
}

impl ResponseType for UserFollowedUpdatesResponseType {
    type OkOutput = UserFollowedUpdatesResponse;

    /// Check if the endpoint response is ok.
    fn is_ok(&self) -> bool {
        matches!(self, Self::Ok(_))
    }

    /// Get the data from the endpoint if the response is ok.
    fn ok(self) -> Option<Self::OkOutput> {
        match self {
            Self::Ok(data) => Some(data),
            _ => None,
        }
    }
}

/// Latest uploaded chapters for the manga that the user has followed, as well as basic
/// related manga information.
///
/// This is the response from the `/api/v2/user/{id}/followed-updates` endpoint.
#[derive(Debug, Deserialize, Clone, PartialEq)]
pub struct UserFollowedUpdatesResponse {
    code: StatusCode,
    status: MangaDexResponseStatus,
    data: UserFollowedUpdatesData,
}

impl UserFollowedUpdatesResponse {
    pub fn code(&self) -> &StatusCode {
        &self.code
    }

    pub fn status(&self) -> &MangaDexResponseStatus {
        &self.status
    }

    pub fn data(&self) -> &UserFollowedUpdatesData {
        &self.data
    }
}

impl ResponseBody for UserFollowedUpdatesResponse {}

#[derive(Debug, Deserialize, Clone, PartialEq)]
pub struct UserFollowedUpdatesData {
    #[serde(flatten)]
    chapters_groups_data: ChaptersDataPartial,
    manga: HashMap<String, UserFollowedUpdatesMangaData>,
}

impl UserFollowedUpdatesData {
    pub fn manga(&self) -> &HashMap<String, UserFollowedUpdatesMangaData> {
        &self.manga
    }
}

#[derive(Debug, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct UserFollowedUpdatesMangaData {
    id: MangaId,
    name: String,
    is_hentai: bool,
    last_chapter: Option<String>,
    last_volume: Option<String>,
    #[serde(rename = "mainCover")]
    main_cover_url: String,
}

impl UserFollowedUpdatesMangaData {
    pub fn id(&self) -> &MangaId {
        &self.id
    }

    pub fn name(&self) -> &String {
        &self.name
    }

    pub fn is_hentai(&self) -> &bool {
        &self.is_hentai
    }

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

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

    pub fn main_cover_url(&self) -> &String {
        &self.main_cover_url
    }
}
