use std::time::Duration;

use night_fury_core::BrowserSession;
use serde_json::json;

use night_fury_cli_core::output::{output_err, output_ok, OutputMode};

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(super) enum DownloadSub {
    Path,
    Wait,
    Unknown,
}

pub(super) fn resolve_download_sub(s: &str) -> DownloadSub {
    match s {
        "path" => DownloadSub::Path,
        "wait" => DownloadSub::Wait,
        _ => DownloadSub::Unknown,
    }
}

pub async fn dispatch(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let sub = parts.first().copied().unwrap_or("");
    match resolve_download_sub(sub) {
        DownloadSub::Path => path(session, &parts[1..], mode).await,
        DownloadSub::Wait => wait(session, &parts[1..], mode).await,
        DownloadSub::Unknown => output_err(
            mode,
            &format!("Unknown download subcommand: {sub}. Use 'path <dir>' or 'wait [timeout_s]'"),
        ),
    }
}

async fn path(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let dir = parts.first().copied().unwrap_or("").trim();
    if dir.is_empty() {
        output_err(mode, "Usage: download path <dir>");
        return;
    }
    match session.set_download_path(dir).await {
        Ok(()) => output_ok(
            mode,
            &format!("Download path set to {dir}"),
            json!({"action": "download_path", "path": dir}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn wait(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let timeout_s: u64 = parts.first().and_then(|s| s.parse().ok()).unwrap_or(30);
    match session
        .wait_for_download(Duration::from_secs(timeout_s))
        .await
    {
        Ok(info) => {
            let human = format!("Downloaded: {} -> {}", info.filename, info.path);
            output_ok(
                mode,
                &human,
                json!({
                    "action": "download_complete",
                    "path": info.path,
                    "filename": info.filename,
                    "url": info.url,
                    "size": info.size,
                }),
            );
        }
        Err(e) => output_err(mode, &e.to_string()),
    }
}

#[cfg(test)]
mod tests {
    use super::{resolve_download_sub, DownloadSub};

    #[test]
    fn resolves_known_subcommands() {
        assert_eq!(resolve_download_sub("path"), DownloadSub::Path);
        assert_eq!(resolve_download_sub("wait"), DownloadSub::Wait);
    }

    #[test]
    fn unknown_subcommand_returns_unknown() {
        assert_eq!(resolve_download_sub(""), DownloadSub::Unknown);
        assert_eq!(resolve_download_sub("list"), DownloadSub::Unknown);
    }
}
