use regex::Regex;
use std::collections::HashSet;
use std::process::Command;

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Process {
    pub pid: i32,
    pub command: String,
}

pub fn find_processes_on_port(port: u16) -> Result<Vec<Process>, String> {
    // ss -tunlp sport = :port
    let output = Command::new("ss")
        .arg("-tunlp")
        .arg(format!("sport = :{}", port))
        .output()
        .map_err(|e| format!("Failed to execute ss: {}", e))?;

    if !output.status.success() {
        return Ok(Vec::new());
    }

    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut processes = HashSet::new();

    // ss -tunlp output example:
    // tcp   LISTEN 0   511  *:3000  *:*  users:(("next-server (v",pid=21661,fd=24))
    // We want to capture the process name and PID from the users clause
    let re = Regex::new(r#"users:\(\("([^"]+)",pid=(\d+),fd=\d+\)\)"#).unwrap();

    for line in stdout.lines() {
        if let Some(cap) = re.captures(line) {
            let command = cap.get(1).map_or("unknown", |m| m.as_str()).to_string();
            if let Some(pid) = cap.get(2).and_then(|m| m.as_str().parse::<i32>().ok()) {
                processes.insert(Process { pid, command });
            }
        }
    }

    Ok(processes.into_iter().collect())
}
