use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use uuid::Uuid;

use super::author::AuthorRef;
use super::genre::GenreRef;
use super::page_analysis::ContentWarning;
use super::patch::Patch;
use super::tag::TagRef;

#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Manga {
    pub id: Uuid,
    pub title: String,
    pub status: String,
    pub alt_titles: Vec<String>,
    pub description: Option<String>,
    pub cover_image_path: Option<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

/// Shape returned by list endpoints. Cards show the title, authors and
/// genres; tags are intentionally elided here to keep the response
/// proportional to what a card actually renders.
#[derive(Debug, Clone, Serialize)]
pub struct MangaCard {
    #[serde(flatten)]
    pub manga: Manga,
    pub authors: Vec<AuthorRef>,
    pub genres: Vec<GenreRef>,
}

/// Shape returned by `GET /mangas/:id`. Adds user-added tags on top of
/// the card fields, plus the deduped content warnings derived by the
/// analysis worker across all the manga's pages.
#[derive(Debug, Clone, Serialize)]
pub struct MangaDetail {
    #[serde(flatten)]
    pub manga: Manga,
    pub authors: Vec<AuthorRef>,
    pub genres: Vec<GenreRef>,
    pub tags: Vec<TagRef>,
    pub content_warnings: Vec<ContentWarning>,
    /// Total bytes of all this manga's stored chapter pages (cover
    /// excluded), over every chapter. `None` when any page is unmeasured
    /// (frontend shows an em-dash); `Some(0)` when there are no pages.
    /// Computed in the DB rather than summed from the chapter list, which
    /// is paginated and would undercount mangas with many chapters.
    pub chapter_storage_bytes: Option<i64>,
}

#[derive(Debug, Clone, Deserialize, Default)]
pub struct NewManga {
    pub title: String,
    #[serde(default)]
    pub status: Option<String>,
    /// Author display names. Looked up case-insensitively; created on
    /// the fly when unseen.
    #[serde(default)]
    pub authors: Vec<String>,
    #[serde(default)]
    pub description: Option<String>,
    #[serde(default)]
    pub alt_titles: Vec<String>,
    #[serde(default)]
    pub genre_ids: Vec<Uuid>,
}

#[derive(Debug, Clone, Deserialize, Default)]
pub struct MangaPatch {
    pub title: Option<String>,
    pub status: Option<String>,
    /// Three-state: missing key leaves the description alone; explicit
    /// `null` clears it; a string sets it. See `Patch` for details.
    #[serde(default)]
    pub description: Patch<String>,
    pub alt_titles: Option<Vec<String>>,
    /// When provided, replaces the manga's authors atomically.
    pub authors: Option<Vec<String>>,
    /// When provided, replaces the manga's genres atomically.
    pub genre_ids: Option<Vec<Uuid>>,
}

// `Patch<T>` lives in `super::patch` so other resources (collections,
// future PATCH endpoints) can reuse the same three-state semantics
// without re-importing through `manga::`.
