use std::{
    env,
    path::{Path, PathBuf},
    process::{Command, ExitCode},
};

fn main() -> ExitCode {
    match run() {
        Ok(()) => ExitCode::SUCCESS,
        Err(err) => {
            eprintln!("{err}");
            ExitCode::FAILURE
        }
    }
}

fn run() -> Result<(), String> {
    let mut args = env::args().skip(1);
    let command = args.next().ok_or_else(|| "missing command".to_string())?;
    let flag = args.next().ok_or_else(|| "missing --profile flag".to_string())?;
    if flag != "--profile" {
        return Err("expected --profile flag".into());
    }
    let profile = PathBuf::from(args.next().ok_or_else(|| "missing profile path".to_string())?);

    match command.as_str() {
        "connect" => connect(&profile),
        "disconnect" => disconnect(&profile),
        _ => Err("unsupported command".into()),
    }
}

fn connect(profile: &Path) -> Result<(), String> {
    #[cfg(target_os = "windows")]
    {
        let wireguard = find_windows_wireguard()?;
        let status = Command::new(wireguard)
            .arg("/installtunnelservice")
            .arg(profile)
            .status()
            .map_err(|err| format!("unable to launch WireGuard runtime: {err}"))?;
        if !status.success() {
            return Err(format!("WireGuard runtime connect failed with status {status}"));
        }
        return Ok(());
    }

    #[cfg(target_os = "macos")]
    {
        let command = format!("wg-quick up '{}'", profile.display());
        let status = Command::new("osascript")
            .arg("-e")
            .arg(format!("do shell script \"{}\" with administrator privileges", command))
            .status()
            .map_err(|err| format!("unable to start tunnel: {err}"))?;
        if !status.success() {
            return Err(format!("macOS tunnel connect failed with status {status}"));
        }
        return Ok(());
    }

    #[allow(unreachable_code)]
    Err("unsupported platform".into())
}

fn disconnect(profile: &Path) -> Result<(), String> {
    #[cfg(target_os = "windows")]
    {
        let wireguard = find_windows_wireguard()?;
        let tunnel_name = profile
            .file_stem()
            .and_then(|value| value.to_str())
            .ok_or_else(|| "invalid profile filename".to_string())?;
        let status = Command::new(wireguard)
            .arg("/uninstalltunnelservice")
            .arg(tunnel_name)
            .status()
            .map_err(|err| format!("unable to launch WireGuard runtime: {err}"))?;
        if !status.success() {
            return Err(format!("WireGuard runtime disconnect failed with status {status}"));
        }
        return Ok(());
    }

    #[cfg(target_os = "macos")]
    {
        let command = format!("wg-quick down '{}'", profile.display());
        let status = Command::new("osascript")
            .arg("-e")
            .arg(format!("do shell script \"{}\" with administrator privileges", command))
            .status()
            .map_err(|err| format!("unable to stop tunnel: {err}"))?;
        if !status.success() {
            return Err(format!("macOS tunnel disconnect failed with status {status}"));
        }
        return Ok(());
    }

    #[allow(unreachable_code)]
    Err("unsupported platform".into())
}

#[cfg(target_os = "windows")]
fn find_windows_wireguard() -> Result<PathBuf, String> {
    let candidates = [
        PathBuf::from(r"C:\Program Files\WireGuard\wireguard.exe"),
        PathBuf::from(r"C:\Program Files (x86)\WireGuard\wireguard.exe"),
    ];

    candidates
        .into_iter()
        .find(|path| path.exists())
        .ok_or_else(|| "required Windows tunnel runtime is not available".to_string())
}
