use serde::Deserialize;

use crate::types::{ChapterId, MangaDexResponseStatus, StatusCode};
use crate::v2::responses::{ErrorResponse, ResponseBody, ResponseType};

#[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq)]
#[serde(untagged)]
pub enum UserChaptersMarkerResponseType {
    Read(UserChaptersReadResponse),
    Unread(UserChaptersUnreadResponse),
    Err(ErrorResponse),
}

impl ResponseType for UserChaptersMarkerResponseType {
    type OkOutput = UserChaptersReadResponse;

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

    /// Get the data from the endpoint if the response is ok.
    ///
    /// TODO: Account for the `UserChaptersReadResponseType::Unread` variant.
    fn ok(self) -> Option<Self::OkOutput> {
        match self {
            Self::Read(data) => Some(data),
            _ => None,
        }
    }
}

/// List of chapters marked as read.
///
/// This is the response from the `/api/v2/user/{id}/marker` endpoint with `read=true`.
#[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq)]
pub struct UserChaptersReadResponse {
    code: StatusCode,
    status: MangaDexResponseStatus,
    data: ChaptersReadData,
}

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

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

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

impl ResponseBody for UserChaptersReadResponse {}

/// List of chapters marked as unread.
///
/// This is the response from the `/api/v2/user/{id}/marker` endpoint with `read=false`.
#[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq)]
pub struct UserChaptersUnreadResponse {
    code: StatusCode,
    status: MangaDexResponseStatus,
    data: ChaptersUnreadData,
}

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

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

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

impl ResponseBody for UserChaptersUnreadResponse {}

#[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq)]
pub struct ChaptersReadData {
    read: Vec<ChapterId>,
}

impl ChaptersReadData {
    pub fn read(&self) -> &Vec<ChapterId> {
        &self.read
    }
}

#[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq)]
pub struct ChaptersUnreadData {
    unread: Vec<ChapterId>,
}

impl ChaptersUnreadData {
    pub fn unread(&self) -> &Vec<ChapterId> {
        &self.unread
    }
}
