use night_fury_core::{BrowserSession, MouseButton};
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 {
        "move" => mouse_move(session, &parts[1..], mode).await,
        "wheel" => mouse_wheel(session, &parts[1..], mode).await,
        "down" => mouse_down(session, &parts[1..], mode).await,
        "up" => mouse_up(session, &parts[1..], mode).await,
        other => output_err(
            mode,
            &format!("Unknown mouse subcommand: {other}. Use 'move', 'wheel', 'down', or 'up'"),
        ),
    }
}

fn parse_button(s: &str) -> MouseButton {
    match s.to_lowercase().as_str() {
        "right" => MouseButton::Right,
        "middle" => MouseButton::Middle,
        _ => MouseButton::Left,
    }
}

async fn mouse_move(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    if parts.len() < 2 {
        output_err(mode, "Usage: mouse move <x> <y>");
        return;
    }
    let x: f64 = match parts[0].parse() {
        Ok(v) => v,
        Err(_) => {
            output_err(mode, "x must be a number");
            return;
        }
    };
    let y: f64 = match parts[1].parse() {
        Ok(v) => v,
        Err(_) => {
            output_err(mode, "y must be a number");
            return;
        }
    };
    match session.mouse_move(x, y).await {
        Ok(msg) => output_ok(mode, &msg, json!({"action": "mouse_move", "x": x, "y": y})),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn mouse_wheel(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    if parts.is_empty() {
        output_err(mode, "Usage: mouse wheel <delta>");
        return;
    }
    let delta: f64 = match parts[0].parse() {
        Ok(v) => v,
        Err(_) => {
            output_err(mode, "delta must be a number");
            return;
        }
    };
    match session.mouse_wheel(0.0, delta).await {
        Ok(msg) => output_ok(mode, &msg, json!({"action": "mouse_wheel", "delta": delta})),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn mouse_down(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let button = parts
        .first()
        .map(|s| parse_button(s))
        .unwrap_or(MouseButton::Left);
    match session.mouse_down(button).await {
        Ok(msg) => output_ok(mode, &msg, json!({"action": "mouse_down"})),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn mouse_up(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let button = parts
        .first()
        .map(|s| parse_button(s))
        .unwrap_or(MouseButton::Left);
    match session.mouse_up(button).await {
        Ok(msg) => output_ok(mode, &msg, json!({"action": "mouse_up"})),
        Err(e) => output_err(mode, &e.to_string()),
    }
}
