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 WsSub {
    Start,
    Messages,
    Unknown,
}

pub(super) fn resolve_ws_sub(s: &str) -> WsSub {
    match s {
        "start" => WsSub::Start,
        "messages" => WsSub::Messages,
        _ => WsSub::Unknown,
    }
}

pub async fn dispatch(session: &BrowserSession, parts: &[&str], mode: OutputMode) {
    let sub = parts.first().copied().unwrap_or("");
    match resolve_ws_sub(sub) {
        WsSub::Start => start(session, mode).await,
        WsSub::Messages => messages(session, mode).await,
        WsSub::Unknown => output_err(
            mode,
            &format!("Unknown ws subcommand: {sub}. Use 'start' or 'messages'"),
        ),
    }
}

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

async fn messages(session: &BrowserSession, mode: OutputMode) {
    match session.get_ws_messages().await {
        Ok(msgs) => {
            let count = msgs.len();
            let mut lines = vec![format!("{count} WebSocket message(s):")];
            for m in &msgs {
                let dir = format!("{:?}", m.direction);
                let preview = if m.data.len() > 80 {
                    format!("{}…", &m.data[..80])
                } else {
                    m.data.clone()
                };
                lines.push(format!("  [{}] {} {}", dir, m.url, preview));
            }
            let human = lines.join("\n");
            let data = msgs
                .iter()
                .map(|m| {
                    json!({
                        "url": m.url,
                        "direction": format!("{:?}", m.direction),
                        "data": m.data,
                        "opcode": m.opcode,
                        "timestamp": m.timestamp,
                    })
                })
                .collect::<Vec<_>>();
            output_ok(mode, &human, json!({"messages": data, "count": count}));
        }
        Err(e) => output_err(mode, &e.to_string()),
    }
}

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

    #[test]
    fn resolves_known_subcommands() {
        assert_eq!(resolve_ws_sub("start"), WsSub::Start);
        assert_eq!(resolve_ws_sub("messages"), WsSub::Messages);
    }

    #[test]
    fn unknown_subcommand_returns_unknown() {
        assert_eq!(resolve_ws_sub(""), WsSub::Unknown);
        assert_eq!(resolve_ws_sub("stop"), WsSub::Unknown);
    }
}
