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 IsSub {
    Visible,
    Checked,
    Enabled,
    Unknown,
}

pub(super) fn resolve_is_sub(s: &str) -> IsSub {
    match s {
        "visible" => IsSub::Visible,
        "checked" => IsSub::Checked,
        "enabled" => IsSub::Enabled,
        _ => IsSub::Unknown,
    }
}

pub async fn dispatch(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let sub = parts.first().copied().unwrap_or("");
    match resolve_is_sub(sub) {
        IsSub::Visible => is_visible(session, &parts[1..], mode).await,
        IsSub::Checked => is_checked(session, &parts[1..], mode).await,
        IsSub::Enabled => is_enabled(session, &parts[1..], mode).await,
        IsSub::Unknown => output_err(
            mode,
            &format!("Unknown is subcommand: {sub}. Use 'visible', 'checked', or 'enabled'"),
        ),
    }
}

async fn is_visible(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let sel = parts.join(" ");
    let sel = sel.trim();
    if sel.is_empty() {
        output_err(mode, "Usage: is visible <css-selector>");
        return;
    }
    match session.is_visible(sel).await {
        Ok(v) => output_ok(
            mode,
            &format!("{v}"),
            json!({"visible": v, "selector": sel}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn is_checked(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let sel = parts.join(" ");
    let sel = sel.trim();
    if sel.is_empty() {
        output_err(mode, "Usage: is checked <css-selector>");
        return;
    }
    match session.is_checked(sel).await {
        Ok(v) => output_ok(
            mode,
            &format!("{v}"),
            json!({"checked": v, "selector": sel}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn is_enabled(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let sel = parts.join(" ");
    let sel = sel.trim();
    if sel.is_empty() {
        output_err(mode, "Usage: is enabled <css-selector>");
        return;
    }
    match session.is_enabled(sel).await {
        Ok(v) => output_ok(
            mode,
            &format!("{v}"),
            json!({"enabled": v, "selector": sel}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

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

    #[test]
    fn resolves_known_subcommands() {
        assert_eq!(resolve_is_sub("visible"), IsSub::Visible);
        assert_eq!(resolve_is_sub("checked"), IsSub::Checked);
        assert_eq!(resolve_is_sub("enabled"), IsSub::Enabled);
    }

    #[test]
    fn unknown_subcommand_returns_unknown() {
        assert_eq!(resolve_is_sub(""), IsSub::Unknown);
        assert_eq!(resolve_is_sub("visibl"), IsSub::Unknown);
        assert_eq!(resolve_is_sub("disabled"), IsSub::Unknown); // opposite of enabled — not supported
    }
}
