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

// =============================================================================
// GET LIKED PLAYLISTS
// =============================================================================

/// Response from /api/playlist/liked_playlist endpoint
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LikedPlaylistsResponse {
    pub playlists: Vec<PlaylistItem>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page_size: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub total_count: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub has_more: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub num_total_results: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub current_page: Option<i32>,
}

// =============================================================================
// GET USER PLAYLISTS (ME)
// =============================================================================

/// Response from /api/playlist/me endpoint
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct UserPlaylistsResponse {
    pub playlists: Vec<PlaylistItem>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page_size: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub total_count: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub has_more: Option<bool>,

    /// Virtual playlists like "Liked Songs", "Sharelist"
    #[serde(skip_serializing_if = "Option::is_none")]
    pub virtual_playlists: Option<Vec<PlaylistItem>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub num_total_results: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub current_page: Option<i32>,
}

// =============================================================================
// GET PLAYLISTS WITH CLIP STATUS
// =============================================================================

/// Response from /api/playlist/me/clip_status endpoint
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PlaylistsWithClipStatusResponse {
    pub playlists: Vec<PlaylistWithClipStatus>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page_size: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub total_count: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub has_more: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub num_total_results: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub current_page: Option<i32>,
}

/// Playlist with clip containment status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlaylistWithClipStatus {
    #[serde(flatten)]
    pub playlist: PlaylistItem,

    /// Whether the target clip is in this playlist
    #[serde(skip_serializing_if = "Option::is_none")]
    pub contains_target_clip: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub current_page: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub num_total_results: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_owned: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub dislike_count: Option<i32>,
}

// =============================================================================
// PLAYLIST ITEM (Reusable)
// =============================================================================

/// Individual playlist item
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlaylistItem {
    pub id: String,

    pub name: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub image_url: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub cover_url: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub playlist_clips_count: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_at: Option<DateTime<Utc>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<DateTime<Utc>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub upvote_count: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub play_count: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_liked: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by_id: Option<Uuid>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by_handle: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_public: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_trashed: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub entity_type: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub playlist_clips: Option<Vec<PlaylistClip>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub current_page: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub num_total_results: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_owned: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub dislike_count: Option<i32>,
}

// =============================================================================
// GET SPECIFIC PLAYLIST
// =============================================================================

/// Response from /api/playlist/{playlist_id} endpoint
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PlaylistDetailsResponse {
    pub id: String,

    pub name: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub image_url: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub cover_url: Option<String>,

    pub playlist_clips_count: i32,

    pub created_at: DateTime<Utc>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<DateTime<Utc>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub upvote_count: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub play_count: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_liked: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_public: Option<bool>,

    pub created_by_id: Uuid,

    pub created_by_handle: String,

    pub created_by_display_name: String,

    /// Paginated clips in playlist
    #[serde(skip_serializing_if = "Option::is_none")]
    pub clips: Option<Vec<PlaylistClip>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page_size: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub cursor: Option<String>,
}

/// Clip in playlist
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PlaylistClip {
    pub id: Uuid,

    pub title: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub image_url: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub audio_url: Option<String>,

    pub creator_handle: String,

    pub creator_display_name: String,

    pub play_count: i32,

    pub upvote_count: i32,

    pub created_at: DateTime<Utc>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub added_to_playlist_at: Option<DateTime<Utc>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub position: Option<i32>,
}
