use night_fury_core::{BrowserSession, RouteAction};
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 {
        "block" => block(session, &parts[1..], mode).await,
        "fulfill" => fulfill(session, &parts[1..], mode).await,
        "capture" => capture(session, &parts[1..], mode).await,
        "list" => list(session, mode).await,
        "clear" => clear(session, mode).await,
        other => output_err(
            mode,
            &format!(
                "Unknown route subcommand: {other}. Use 'block', 'fulfill', 'capture', 'list', or 'clear'"
            ),
        ),
    }
}

async fn block(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let pattern = parts.first().copied().unwrap_or("").trim();
    if pattern.is_empty() {
        output_err(mode, "Usage: route block <pattern>");
        return;
    }
    match session.add_route(pattern, RouteAction::Block).await {
        Ok(msg) => output_ok(
            mode,
            &msg,
            json!({"action": "route_block", "pattern": pattern}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn fulfill(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    if parts.len() < 3 {
        output_err(mode, "Usage: route fulfill <pattern> <status> <body>");
        return;
    }
    let pattern = parts[0];
    let status: u16 = match parts[1].parse() {
        Ok(s) => s,
        Err(_) => {
            output_err(
                mode,
                "Usage: route fulfill <pattern> <status> <body> — status must be an integer",
            );
            return;
        }
    };
    let body = parts[2..].join(" ");
    let action = RouteAction::Fulfill {
        status,
        headers: vec![],
        body: body.clone(),
    };
    match session.add_route(pattern, action).await {
        Ok(msg) => output_ok(
            mode,
            &msg,
            json!({"action": "route_fulfill", "pattern": pattern, "status": status, "body": body}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn capture(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let pattern = parts.first().copied().unwrap_or("").trim();
    if pattern.is_empty() {
        output_err(mode, "Usage: route capture <pattern>");
        return;
    }
    match session.capture_responses(pattern).await {
        Ok(msg) => output_ok(
            mode,
            &msg,
            json!({"action": "route_capture", "pattern": pattern}),
        ),
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn list(session: &BrowserSession, mode: OutputMode) {
    match session.get_captured_responses().await {
        Ok(responses) => {
            let count = responses.len();
            let mut lines = vec![format!("{count} captured response(s):")];
            for r in &responses {
                lines.push(format!("  [{}] {}", r.status, r.url));
            }
            let human = lines.join("\n");
            let data = responses
                .iter()
                .map(|r| {
                    json!({
                        "url": r.url,
                        "status": r.status,
                        "body": r.body,
                    })
                })
                .collect::<Vec<_>>();
            output_ok(mode, &human, json!({"responses": data, "count": count}));
        }
        Err(e) => output_err(mode, &e.to_string()),
    }
}

async fn clear(session: &BrowserSession, mode: OutputMode) {
    match session.clear_routes().await {
        Ok(msg) => output_ok(mode, &msg, json!({"action": "route_clear"})),
        Err(e) => output_err(mode, &e.to_string()),
    }
}
