use serde::{Deserialize, Serialize};

/// A YouTube channel the user is subscribed to, as imported from Takeout.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Channel {
    pub id: String,
    pub title: String,
    pub url: String,
}

/// A video as described by a channel's public Atom feed.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Video {
    pub id: String,
    pub channel_id: String,
    pub title: String,
    pub description: String,
    /// Unix seconds, so feed ordering is a plain indexed sort.
    pub published: i64,
    pub thumb_url: String,
    pub views: i64,
    pub is_short: bool,
}

/// A channel plus how many of its videos we currently know about.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChannelWithCount {
    pub id: String,
    pub title: String,
    pub url: String,
    pub video_count: i64,
    pub downloaded_count: i64,
    /// Why the last refresh of this channel failed, if it did.
    pub last_error: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DownloadState {
    Queued,
    Running,
    Done,
    Failed,
    Cancelled,
}

impl DownloadState {
    pub fn as_str(&self) -> &'static str {
        match self {
            DownloadState::Queued => "queued",
            DownloadState::Running => "running",
            DownloadState::Done => "done",
            DownloadState::Failed => "failed",
            DownloadState::Cancelled => "cancelled",
        }
    }

    pub fn from_str(s: &str) -> Option<Self> {
        match s {
            "queued" => Some(DownloadState::Queued),
            "running" => Some(DownloadState::Running),
            "done" => Some(DownloadState::Done),
            "failed" => Some(DownloadState::Failed),
            "cancelled" => Some(DownloadState::Cancelled),
            _ => None,
        }
    }
}

/// A feed row: video metadata joined with whatever we know about its download.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeedItem {
    pub id: String,
    pub channel_id: String,
    pub channel_title: String,
    pub title: String,
    pub description: String,
    pub published: i64,
    pub thumb_url: String,
    pub thumb_path: Option<String>,
    pub views: i64,
    pub is_short: bool,
    pub state: Option<DownloadState>,
    pub path: Option<String>,
    pub pct: Option<f64>,
    pub error: Option<String>,
    /// Seconds watched, and the video's length — drives the feed progress bar.
    pub position: Option<f64>,
    pub duration: Option<f64>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct FeedFilter {
    pub channel_id: Option<String>,
    pub search: Option<String>,
    #[serde(default)]
    pub downloaded_only: bool,
    #[serde(default)]
    pub hide_shorts: bool,
    pub limit: Option<i64>,
}

/// Result of checking that the external binaries we shell out to exist.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Prereqs {
    pub yt_dlp: Option<String>,
    pub ffmpeg: Option<String>,
    pub library_path: String,
}

/// What a replacing Takeout import would add and destroy.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImportPreview {
    pub incoming: i64,
    pub removed_channels: i64,
    pub removed_videos: i64,
    pub removed_downloads: i64,
}
