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 TouchSub {
    Tap,
    Swipe,
    Unknown,
}

pub(super) fn resolve_touch_sub(s: &str) -> TouchSub {
    match s {
        "tap" => TouchSub::Tap,
        "swipe" => TouchSub::Swipe,
        _ => TouchSub::Unknown,
    }
}

pub async fn dispatch(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let sub = parts.first().copied().unwrap_or("");
    match resolve_touch_sub(sub) {
        TouchSub::Tap => tap(session, &parts[1..], mode).await,
        TouchSub::Swipe => swipe(session, &parts[1..], mode).await,
        TouchSub::Unknown => output_err(
            mode,
            &format!(
                "Unknown touch subcommand: {sub}. Use 'tap <x> <y>' or 'swipe <x1> <y1> <x2> <y2>'"
            ),
        ),
    }
}

async fn tap(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    if parts.len() < 2 {
        output_err(mode, "Usage: touch tap <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.tap(x, y).await {
        Ok(msg) => output_ok(mode, &msg, json!({"action": "touch_tap", "x": x, "y": y})),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn swipe(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    if parts.len() < 4 {
        output_err(mode, "Usage: touch swipe <x1> <y1> <x2> <y2>");
        return;
    }
    let x1: f64 = match parts[0].parse() {
        Ok(v) => v,
        Err(_) => {
            output_err(mode, "x1 must be a number");
            return;
        }
    };
    let y1: f64 = match parts[1].parse() {
        Ok(v) => v,
        Err(_) => {
            output_err(mode, "y1 must be a number");
            return;
        }
    };
    let x2: f64 = match parts[2].parse() {
        Ok(v) => v,
        Err(_) => {
            output_err(mode, "x2 must be a number");
            return;
        }
    };
    let y2: f64 = match parts[3].parse() {
        Ok(v) => v,
        Err(_) => {
            output_err(mode, "y2 must be a number");
            return;
        }
    };
    match session.swipe(x1, y1, x2, y2).await {
        Ok(msg) => output_ok(
            mode,
            &msg,
            json!({"action": "touch_swipe", "x1": x1, "y1": y1, "x2": x2, "y2": y2}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

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

    #[test]
    fn resolves_known_subcommands() {
        assert_eq!(resolve_touch_sub("tap"), TouchSub::Tap);
        assert_eq!(resolve_touch_sub("swipe"), TouchSub::Swipe);
    }

    #[test]
    fn unknown_subcommand_returns_unknown() {
        assert_eq!(resolve_touch_sub(""), TouchSub::Unknown);
        assert_eq!(resolve_touch_sub("pinch"), TouchSub::Unknown);
    }
}
