ziro 0.0.16

跨平台端口管理工具 - 快速查找和终止占用端口的进程
mod cli;
mod file;
mod icons;
mod port;
mod process;
mod term;
mod theme;
mod top;
mod ui;

use anyhow::Result;
use clap::Parser;
use cli::{Cli, Commands};
use colored::Colorize;
use console::Style;
use std::env;

fn main() {
    if let Err(e) = run() {
        ui::display_error(&e);
        std::process::exit(1);
    }
}

fn run() -> Result<()> {
    let cli = Cli::parse();
    let profile = term::detect_profile(&cli);
    term::apply_profile_env(&profile);
    term::set_global_profile(profile);

    // 如果请求版本信息,显示并退出
    if cli.version {
        display_version();
        return Ok(());
    }

    match cli.command {
        Some(Commands::Find { ports }) => handle_find(ports)?,
        Some(Commands::Kill { ports, force }) => handle_kill(ports, force)?,
        Some(Commands::List) => handle_list()?,
        Some(Commands::Remove {
            paths,
            force,
            recursive,
            dry_run,
            verbose,
            anyway,
        }) => handle_remove(paths, force, recursive, dry_run, verbose, anyway)?,
        Some(Commands::Top {
            interval,
            limit,
            cpu,
            cmd,
            once,
        }) => handle_top(interval, limit, cpu, cmd, once)?,
        None => {
            // 当没有提供子命令时显示帮助信息
            println!("使用 'ziro --help' 查看可用命令");
        }
    }

    Ok(())
}

// CLI 兼容性:保留参数定义,但能力检测已集中到 term::detect_profile/ apply_profile_env。

fn display_version() {
    let version = env!("CARGO_PKG_VERSION");

    // 使用 console 库,它会自动检测终端支持并处理兼容性
    // console 库会自动启用 Windows 10+ 上的 ANSI 支持
    let cyan = Style::new().cyan().bold();
    let white = Style::new().white().bold();

    println!(
        "{} {}",
        cyan.apply_to("ziro"),
        white.apply_to(format!("v{version}"))
    );
}

fn handle_find(ports: Vec<u16>) -> Result<()> {
    if ports.is_empty() {
        println!("请指定至少一个端口号");
        return Ok(());
    }

    // 批量查找所有端口
    let port_infos = port::find_processes_by_ports(&ports)?;

    // 使用树形结构展示
    ui::display_ports_tree(&ports, port_infos);

    Ok(())
}

fn handle_kill(ports: Vec<u16>, force: bool) -> Result<()> {
    if ports.is_empty() {
        println!("请指定至少一个端口号");
        return Ok(());
    }

    // 查找所有指定端口的进程
    let port_infos = port::find_processes_by_ports(&ports)?;

    if port_infos.is_empty() {
        println!("未找到占用指定端口的进程");
        for &port in &ports {
            ui::display_port_not_found(port);
        }
        return Ok(());
    }

    if force {
        // 强制模式:直接终止所有找到的进程
        let pids: Vec<u32> = port_infos.iter().map(|info| info.process.pid).collect();
        let results = process::kill_processes_force(&pids);

        // 显示强制模式的结果
        ui::display_kill_results_force(&port_infos, &results);
    } else {
        // 交互模式:让用户选择要终止的进程
        let selected = ui::select_processes_to_kill(port_infos)?;

        if selected.is_empty() {
            return Ok(());
        }

        // 终止选中的进程
        let pids: Vec<u32> = selected.iter().map(|info| info.process.pid).collect();
        let results = process::kill_processes(&pids);

        // 显示结果
        ui::display_kill_results(&results);
    }

    Ok(())
}

fn handle_list() -> Result<()> {
    let port_infos = port::list_all_ports()?;
    ui::display_ports_tree_all(port_infos);
    Ok(())
}

fn handle_top(interval: f32, limit: usize, cpu: bool, cmd: bool, once: bool) -> Result<()> {
    let opts = top::TopOptions {
        interval,
        limit,
        show_cpu: cpu,
        show_cmd: cmd,
        once,
    };
    top::run_top(opts)
}

fn handle_remove(
    paths: Vec<std::path::PathBuf>,
    force: bool,
    recursive: bool,
    dry_run: bool,
    verbose: bool,
    anyway: bool,
) -> Result<()> {
    if paths.is_empty() {
        println!("请指定至少一个文件或目录路径");
        return Ok(());
    }

    // 验证路径安全性
    file::validate_paths(&paths)?;

    // 收集要删除的文件信息
    let files = file::collect_files_to_remove(&paths, recursive)?;

    if files.is_empty() {
        println!("没有找到匹配的文件或目录");
        return Ok(());
    }

    // 显示预览并确认
    if !ui::confirm_deletion(&files, force, dry_run)? {
        println!("{}", "操作已取消".bright_yellow());
        return Ok(());
    }

    // 执行删除
    let results = file::remove_files(&files, dry_run, verbose, anyway);

    // 显示结果
    ui::display_removal_results(&results, dry_run, verbose);

    Ok(())
}