porta-rs 0.1.1

Zero-trust CGNAT bypass via WireGuard tunnel
use anyhow::Result;
use clap::Args;

use crate::config::{load_config, Role};
use crate::ufw::rules::UfwManager;

#[derive(Args)]
pub struct RemovePortArgs {
    /// ID of the port mapping to remove
    pub id: String,

    /// Skip UFW rule removal
    #[arg(long)]
    pub no_ufw: bool,
}

pub fn execute(args: &RemovePortArgs) -> Result<()> {
    let mut config = load_config()?;

    // Find the port mapping before removing
    let port_to_remove = config.ports().iter().find(|p| p.id == args.id).cloned();

    let initial_len = config.ports().len();
    config.ports_mut().retain(|p| p.id != args.id);

    if config.ports().len() == initial_len {
        return Err(anyhow::anyhow!("Port mapping '{}' not found", args.id));
    }

    config.save()?;

    // Remove UFW rule if on server
    if config.role() == Role::Server && !args.no_ufw {
        if let Some(port) = &port_to_remove {
            let ufw = UfwManager::new();
            if ufw.is_active() {
                match ufw.deny_port(port.remote_port, &port.protocol) {
                    Ok(()) => {
                        println!("\x1b[1;32m✓ UFW rule removed: {} {}\x1b[0m", port.remote_port, port.protocol);
                    }
                    Err(e) => {
                        println!("\x1b[1;33m⚠ Failed to remove UFW rule: {}\x1b[0m", e);
                    }
                }
            }
        }
    }

    println!("\n\x1b[1;32m✓ Port mapping '{}' removed\x1b[0m\n", args.id);

    Ok(())
}