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

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

pub async fn dispatch(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let sub = parts.first().copied().unwrap_or("");
    match sub {
        "new" => new(session, &parts[1..], mode).await,
        "switch" => switch(session, &parts[1..], mode).await,
        "list" => list(session, mode).await,
        "close" => close(session, &parts[1..], mode).await,
        other => output_err(
            mode,
            &format!(
                "Unknown tab subcommand: {other}. Use 'new [url]', 'switch <idx>', 'list', or 'close [idx]'"
            ),
        ),
    }
}

async fn new(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let url = parts.first().copied().filter(|s| !s.is_empty());
    match session.new_tab(url).await {
        Ok(idx) => output_ok(
            mode,
            &format!("Opened new tab [{idx}]"),
            json!({"action": "tab_new", "idx": idx}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn switch(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let idx_str = parts.first().copied().unwrap_or("").trim();
    match idx_str.parse::<usize>() {
        Ok(idx) => match session.switch_tab(idx).await {
            Ok(msg) => output_ok(mode, &msg, json!({"action": "tab_switch", "idx": idx})),
            Err(e) => output_err(mode, &e.to_string()),
        },
        Err(_) => output_err(mode, "Usage: tab switch <idx>"),
    }
}

async fn list(session: &BrowserSession, mode: OutputMode) {
    match session.list_tabs().await {
        Ok(tabs) => {
            let count = tabs.len();
            let mut lines = vec![format!("{count} tab(s):")];
            for tab in &tabs {
                let active_marker = if tab.active { " (active)" } else { "" };
                let prefix = if tab.active { "→" } else { " " };
                lines.push(format!(
                    "{prefix} [{}] {} — {}{}",
                    tab.idx, tab.title, tab.url, active_marker
                ));
            }
            let human = lines.join("\n");
            let data = tabs
                .iter()
                .map(|t| {
                    json!({
                        "idx": t.idx,
                        "title": t.title,
                        "url": t.url,
                        "active": t.active,
                    })
                })
                .collect::<Vec<_>>();
            output_ok(mode, &human, json!({"tabs": data, "count": count}));
        }
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn close(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let idx = parts.first().and_then(|s| s.parse::<usize>().ok());
    match session.close_tab(idx).await {
        Ok(msg) => output_ok(mode, &msg, json!({"action": "tab_close", "idx": idx})),
        Err(e) => output_err(mode, &e.to_string()),
    }
}
