use std::{io, fs, fmt, os, path, process, time};
use fmt::Display;
use os::fd::{AsFd, AsRawFd};
use os::unix::{fs::PermissionsExt, process::CommandExt};
use path::{Path, PathBuf};
use std::sync::OnceLock;

use nix::sched::{clone, CloneCb, CloneFlags, setns};
use nix::sys::{signal::{kill, Signal}, wait::{waitpid, WaitPidFlag}};
use nix::unistd::{dup2, pivot_root, setgid, setgroups, sethostname, setuid, Gid, Pid, Uid, User};
use nix::mount::{mount, MntFlags, MsFlags, umount2};
use uuid;
use toml;
use serde::{Deserialize, Serialize};
use clap::Parser;

use error::{Result, RockerError};
mod error;
use network::{create_network, remove_network};
mod network;

static WORKSPACE: &str = "/home/rocker";
static USER_NAME: &str = "rocker";
static INFO_FILE: &str = "info.toml";
static mut STACK: [u8; 1024*1024*1] = [0; 1024*1024*1];
static CLONE_FLAG: i32 = 0b1101100000000100000000000000000;  // CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNET;
static START_T: OnceLock<time::Instant> = OnceLock::new();

static LOGO: &str = r#"
 ____                    __                      
/\  _`\                 /\ \                     
\ \ \L\ \    ___     ___\ \ \/'\      __   _ __  
 \ \ ,  /   / __`\  /'___\ \ , <    /'__`\/\`'__\
  \ \ \\ \ /\ \L\ \/\ \__/\ \ \\`\ /\  __/\ \ \/ 
   \ \_\ \_\ \____/\ \____\\ \_\ \_\ \____\\ \_\ 
    \/_/\/ /\/___/  \/____/ \/_/\/_/\/____/ \/_/ 
"#;

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct RockerArgs {
    // --wait/--log --run /bin/bash --image busybox 
    #[arg(long)]
    run: Option<String>,
    #[arg(long)]
    image: Option<String>,
    #[arg(long)]
    // --volume "/tmp/test1:tmp/test1,/tmp/test2:tmp/test2"
    volume: Option<String>,  
    #[arg(long)]
    // --env "a=1,b=2,c=3"
    env: Option<String>,

    // --run /bin/bash --exec container_id
    #[arg(long)]
    exec: Option<String>,

    #[arg(long)]
    log: bool,
    #[arg(long)]
    wait: bool,

    // --logs container_id
    #[arg(long)]
    logs: Option<String>,

    // --ps
    #[arg(long)]
    ps: bool,
    // --psa
    #[arg(long)]
    psa: bool,
    
    // rm "container_id_1, container_id_2, container_id_3"
    #[arg(long)]
    rm: Option<String>,

    // stop "container_id_1, container_id_2, container_id_3"
    #[arg(long)]
    stop: Option<String>,

    // start container_id_1
    #[arg(long)]
    restart: Option<String>,
    
}

macro_rules! rocker_println {
    ($($arg:tt)*) => {
        if cfg!(debug_assertions) {
            println!($($arg)*);
        }
    };
}

/// 从images解压到volumes
fn extend_image(image_name: &String) -> Result<PathBuf> {
    // 源文件
    let image_path = Path::new(WORKSPACE).join("images").join(image_name);
    if image_path.exists() == false {
        return Err(RockerError::from(io::Error::new(io::ErrorKind::NotFound, "未找到镜像")));
    }
    let image_path_str = image_path.to_str().unwrap();  // 安全的unwrap

    // volumes只读层
    let volume_path = Path::new(WORKSPACE).join("volumes").join(image_name);
    if volume_path.exists() {
        return Ok(volume_path);
    } else {
        create_dir(&volume_path, true)?;
    }
    let volume_path_str = volume_path.to_str().unwrap();  // 安全的unwrap

    // 解压缩
    let out = process::Command::new("tar")
        .arg("-xvf")
        .arg(image_path_str)
        .arg("-C")
        .arg(volume_path_str)
        .output()?;

    if out.status.success() {
        println!("解压缩完毕: {image_name:?}");
        // 把解压缩后的文件全部给 rocker:rocker
        let _ = process::Command::new("chown")
            .arg("-R")
            .arg("rocker:rocker")
            .arg(volume_path_str)
            .output()?;
        Ok(volume_path)
    } else {
        // 删除 volume_path
        std::fs::remove_dir_all(volume_path)?;
        let std_err = String::from_utf8_lossy(&out.stderr);
        Err(RockerError::from(io::Error::new(io::ErrorKind::Other, format!("解压缩镜像失败: {std_err}"))))
    }
}


fn init_container_overlay<P: AsRef<Path>>(volume_path: P, upper_path: P, merged_path: P) -> Result<()> {
    let lower_dir = volume_path.as_ref().to_string_lossy().to_string();
    let upper_dir = upper_path.as_ref().to_string_lossy().to_string();
    let merged_dir = merged_path.as_ref().to_string_lossy().to_string();

    let dirs = format!("lowerdir={lower_dir},upperdir={upper_dir},workdir={merged_dir}");
    let out = process::Command::new("mount")
        .arg("-t")
        .arg("overlay")
        .arg("overlay")
        .arg("-o")
        .arg(dirs)
        .arg(merged_dir)
        .output()?;
    
    if out.status.success() {
        println!("容器文件系统创建完成");
    } else {
        let std_err = String::from_utf8_lossy(&out.stderr);
        return Err(RockerError::from(io::Error::new(io::ErrorKind::Other, format!("容器文件系统创建失败: {std_err:?}"))));
    }
    Ok(())
}

fn init_container_custom_volume<P: AsRef<Path>>(container_merged_path: P, custom_volume_s: &String) -> Result<()> {
    for custom_volume in custom_volume_s.split(",") {
        let custom_volume_v = custom_volume.split(":").collect::<Vec<&str>>();
        if custom_volume_v.len() < 2 {
            return Err(RockerError::OtherError(format!("volume 参数格式不正确: {custom_volume}")));
        }
        let host_path = custom_volume_v[0];
        let container_path_buf = {
            if custom_volume_v[1].starts_with("/") {
                container_merged_path.as_ref().join(&custom_volume_v[1][1..])
            } else {
                container_merged_path.as_ref().join(&custom_volume_v[1])
            }
        };
        let container_path = container_path_buf.to_string_lossy().to_string();

        // 创建宿主机和容器内的目录
        create_dir(Path::new(host_path), true)?;
        create_dir(&container_path, true)?;

        // 绑定
        let out = process::Command::new("mount")
            .arg("-o")
            .arg("bind")
            .arg(host_path)
            .arg(container_path)
            .output()?;

        if out.status.success() {
            println!("创建自定义 volume: {custom_volume:?}");
        } else {
            let std_err = String::from_utf8_lossy(&out.stderr);
            return Err(RockerError::OtherError(format!("创建volume失败: {std_err}")))
        }
    }
    Ok(())
}


fn init_container_env(env: &String) -> Result<()>{
    for (k, _) in std::env::vars(){
        std::env::remove_var(k);
    }
    let mut env_vec = if env.starts_with("./") || env.starts_with("/") {
        // 读取出路径指定的文件作为env
        let env_text = fs::read_to_string(env)?;
        env_text.lines().map(String::from).collect::<Vec<String>>()
    } else {
        env.split(",").map(String::from).collect::<Vec<String>>()
    };

    env_vec.push(r#"PS1=\u\h:\W\$ "#.to_string());

    for item_env in env_vec.iter() {
        let item_env_v = item_env.split("=").collect::<Vec<&str>>();
        if item_env_v.len() == 2 {
            std::env::set_var(item_env_v[0], item_env_v[1])
        } else {
            if item_env.len() > 0 {
                println!("env 格式不正确: {item_env}")
            }
        }
    }
    Ok(())
}


fn init_container_pivot<P: AsRef<Path>>(merged_path: P) -> Result<()> {
    // 在我们没有设置 chroot之前, 需要先把所有挂载点的传播类型改为 private, 避免进程中的系统调用污染全局
    mount(None::<&str>, "/", None::<&str>, MsFlags::MS_PRIVATE | MsFlags::MS_REC, None::<&str>)?;

    // 修改overlayfs 为rootfs
    std::env::set_current_dir(merged_path)?;
    let pwd_path = std::env::current_dir()?;
    let pwd_str = pwd_path.to_string_lossy().to_string();

    // 挂载bind
    mount(Some(pwd_str.as_str()), pwd_str.as_str(), Some("bind"), MsFlags::MS_BIND | MsFlags::MS_REC, Some(""))?;
    
    // 创建 rootfs/.pivot_root 目录用于存储 old_root
    let pivot_root_dir = format!("{pwd_str}/.pivot_root");

    // 将系统rootfs切换到新的rootfs, 并设置权限
    create_dir(&pivot_root_dir, true)?;
    pivot_root(pwd_str.as_str(), pivot_root_dir.as_str())?;

    // 修改当前进程工作目录(注意我们之前已经到rootfs内, 并且把根目录设置完毕了)
    std::env::set_current_dir("/")?;

    // 卸载 old_root, 并删除临时文件
    umount2(".pivot_root", MntFlags::MNT_DETACH).unwrap();
    std::fs::remove_dir(".pivot_root").unwrap();
    Ok(())
}


fn init_container_mount() -> Result<()> {
    // 挂载proc
    let mount_flags = MsFlags::MS_NODEV | MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID;
    mount(Some("proc"), "/proc", Some("proc"), mount_flags, Some(""))?;  

    // 挂载dev
    mount(Some("tmpfs"), "/dev", Some("tmpfs"), mount_flags, Some("mode=755"))?;  
    Ok(())
}

fn init_container_log() -> Result<()> {
    let log_path = Path::new("logs");
    let log_file = fs::OpenOptions::new()
        .append(true)
        .write(true)
        .read(true)
        .open(log_path.join("log"))?;
    let log_fd_raw = log_file.as_raw_fd();
    dup2(log_fd_raw, 1)?;
    dup2(log_fd_raw, 2)?;
    Ok(())
}


fn init_container_user(uid: Uid, gid: Gid) -> Result<()>{
    setgid(gid)?;
    setgroups(&[gid])?;
    setuid(uid)?;
    Ok(())
}

fn create_dir<P: AsRef<Path>>(path: P, is_any:bool) -> Result<()> {
    fs::create_dir_all(&path)?;
    if is_any {
        fs::set_permissions(&path, PermissionsExt::from_mode(0o777))?;
    }
    Ok(())
}

fn check_container_is_running(pid: &Pid, main_exe: &Path) -> Result<bool> {
    // 检查pid对应的exe是否和外部传过来的相同
    let child_exe_s= format!("/proc/{pid}/exe");
    let child_exe_path = Path::new(child_exe_s.as_str());
    match fs::read_link(child_exe_path) {
        Ok(child_exe_path) if child_exe_path == main_exe => Ok(false),
        _ => Ok(true)
    }
}

fn init_exec_ns(pid: i32) -> Result<()>{
    // 把当前进程加入到指定pid的namespace
    for ns_name in vec!["ipc", "uts", "net", "pid", "mnt"] {
        let ns_path = format!("/proc/{pid}/ns/{ns_name}");
        let ns_fild = fs::File::open(ns_path)?;
        setns(ns_fild.as_fd(), CloneFlags::from_bits_retain(0))?    }
    Ok(())
}

fn create_pause(container_root_pause_path: &Path) -> Result<()> {
    fs::OpenOptions::new()
        .write(true)
        .create(true)
        .read(true)
        .open(container_root_pause_path)?;
    Ok(())
}

fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, container_merged_pause_path: &PathBuf) -> Result<i32>{
    match unsafe {clone(cb, STACK.as_mut_slice(), clong_flags, None)} {
        Ok(child_pid) => {
            {  // 执行成功就保存吧~
                let mut _container_info = container_info.clone();
                _container_info.pid = child_pid.as_raw();
                let _ = _container_info.flush();
            }

            // exec之前的步骤
            create_network(&container_info.id, child_pid.as_raw());
            // 删除 pause标志文件, 解开阻塞, 使其执行exec
            for _ in 0..500 {
                std::thread::sleep(std::time::Duration::from_millis(10));
                if std::fs::remove_file(container_merged_pause_path).is_ok() {
                    break;
                }
            }

            // 检查是否执行exec了
            let main_exe = std::env::current_exe()?;
            for _ in 0..500 {
                std::thread::sleep(std::time::Duration::from_millis(10));
                if let Ok(true) = check_container_is_running(&child_pid, &main_exe) {
                    break;
                }
            }
            println!("{} 启动用时: {}ms", container_info.id, START_T.get().unwrap().elapsed().as_millis());
            
            // wait
            if container_info.wait {
                match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) {
                    Ok(status) => {
                        println!("exit: {status:?}");
                    }
                    Err(e) => {
                        println!("{child_pid} wait err: {e}");
                    }
                }
            }
            Ok(child_pid.as_raw())
        }
        Err(e) => {
            Err(RockerError::OtherError(format!("clone err: {e}")))
        }
    }
}

fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -> Result<i32> {
    // 禁止同时wait和log
    if container_info.wait && container_info.log {
        return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string()));
    }

    let clone_flags;

    let container_work_path = Path::new(WORKSPACE).join("containers").join(&container_info.id);
    let container_upper_path = container_work_path.join("upper");
    let container_merged_path = container_work_path.join("merged");
    let container_merged_pause_path = container_work_path.join("merged").join("pause");
    let container_root_pause_path = Path::new("/pause");

    // 初始化容器工作目录
    if create_dir(&container_work_path, true).is_ok() && create_dir(&container_upper_path, true).is_ok() && create_dir(&container_merged_path, true).is_ok() {
        println!("容器工作目录创建成功");
    } else {
        return Err(RockerError::OtherError("容器工作目录创建失败".to_string()));
    }

    let rocker_user_info =  User::from_name(USER_NAME)?.ok_or(RockerError::OtherError(format!("没找到 用户: {USER_NAME}")))?;
    let rocker_uid = rocker_user_info.uid;
    let rocker_gid = rocker_user_info.gid;

    let _cb = if let Some(exec_cmd) = is_exec_cmd {
        let _cb = || {
            init_exec_ns(container_info.pid).unwrap();
            init_container_env(&Default::default()).unwrap();
            init_container_user(rocker_uid, rocker_gid).unwrap();

            create_pause(container_root_pause_path).unwrap();
            while container_merged_pause_path.exists() {
                std::thread::sleep(std::time::Duration::from_millis(10));
            }

            let cmd_vec = exec_cmd.split(" ").collect::<Vec<&str>>();
            let err = process::Command::new(cmd_vec[0])
                .args(&cmd_vec[1..])
                .exec();
            println!("🔴 execv {cmd_vec:?}失败: {err:?}");
            0isize
        };
        clone_flags = CloneFlags::empty();
        Box::new(_cb) as CloneCb
    } else {
        let _cb = || {
            let volume_path = extend_image(&container_info.image).unwrap();
            init_container_overlay(&volume_path, &container_upper_path, &container_merged_path).unwrap();
            if container_info.volume.len() > 3 { // .:.  最少也要有3个字符吧
                init_container_custom_volume(&container_merged_path, &container_info.volume).unwrap();
            }
            sethostname(USER_NAME).unwrap();
            init_container_env(&container_info.env).unwrap();
            init_container_pivot(&container_merged_path).unwrap();
            init_container_mount().unwrap();
            if container_info.log {
                init_container_log().unwrap();
            }
            init_container_user(rocker_uid, rocker_gid).unwrap();

            create_pause(&container_root_pause_path).unwrap();
            while container_root_pause_path.exists() {
                std::thread::sleep(std::time::Duration::from_millis(10));
            }

            let cmd_vec = container_info.run.split(" ").collect::<Vec<&str>>();
            let err = process::Command::new(cmd_vec[0])
                .args(&cmd_vec[1..])
                .exec();
            println!("🔴 execv {cmd_vec:?}失败: {err:?}");
            0isize
        };
        clone_flags = CloneFlags::from_bits_truncate(CLONE_FLAG);
        Box::new(_cb) as CloneCb
    };

    start(container_info, _cb, clone_flags, &container_merged_pause_path)
}

#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
enum ContainerStatus {
    READY,
    RUNNING,
    STOP,
}

impl Display for ContainerStatus {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::READY => write!(f, "😀"),
            Self::RUNNING => write!(f, "🟢"),
            Self::STOP => write!(f, "🔴"),
        }
    }
    
}


#[derive(Deserialize, Serialize, Debug, Clone)]
struct ContainerInfo {
    id: String,
    pid: i32,
    status: ContainerStatus,

    run: String,  // /bin/bash
    image: String,  // busybox
    volume: String,  // /root/tmp:/root/tmp,/root/tmp1:/root/tmp1
    env: String,  // a=1,b=2,c=3 或者 env文件路径
    log: bool,
    wait: bool,
}

impl ContainerInfo {
    fn flush(&self) -> Result<()>{
        let container_info_path = Path::new(WORKSPACE).join("containers").join(&self.id).join(INFO_FILE);
        let toml_str = toml::to_string(&self)?;
        fs::write(container_info_path, toml_str)?;
        Ok(())
    }
}

impl Display for ContainerInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let volume: String = self.volume.chars().take(20).collect();
        let env: String = self.env.chars().take(20).collect();
        write!(f, "\x1b[4m{:<10} {:<8} {:<10} {:<20} {:<20} {:<20} {:<10}\x1b[24m", self.id, self.pid, self.image, self.run, volume, env, &self.status)
    }
}

fn save_container_info(args: &RockerArgs, container_id: &String, pid: i32) -> Result<()> {
    let container_info_path = Path::new(WORKSPACE).join("containers").join(container_id).join(INFO_FILE);
    let container_info = ContainerInfo {
        id: container_id.clone(),
        pid: pid,
        run: args.run.as_ref().unwrap().clone(),
        image: args.image.as_ref().unwrap().clone(),
        volume: args.volume.clone().unwrap_or("".to_string()),
        env: args.env.clone().unwrap_or("".to_string()),
        status: ContainerStatus::READY,
        log: args.log,
        wait: args.wait,
    };
    let toml_str = toml::to_string(&container_info)?;
    fs::write(container_info_path, toml_str)?;
    Ok(())
}

fn get_container_info(container_id: &str) -> Result<ContainerInfo> {
    let container_work_path = Path::new(WORKSPACE).join("containers").join(container_id);
    let container_info_path = container_work_path.join(INFO_FILE);
    let info_str = fs::read_to_string(container_info_path)?;
    let mut container_info: ContainerInfo = toml::from_str(&info_str)?;
    
    // 判断是否正在运行, 进入proc/pid/判断当前进程网络中是否有下面的设备
    let dev_path = Path::new("/proc").join(container_info.pid.to_string()).join("net").join("dev");
    let is_running = if let Ok(dev_text) = fs::read_to_string(dev_path){
        let slave_veth_name = format!("ro_{container_id}_3");
        dev_text.lines().any(|l|l.starts_with(&slave_veth_name))
    } else {
        false
    };
    if is_running {
        container_info.status = ContainerStatus::RUNNING;
    } else {
        container_info.status = ContainerStatus::STOP;
    }
    Ok(container_info)
}

fn get_all_container_info() -> Result<Vec<ContainerInfo>> {
    let containers_path = Path::new(WORKSPACE).join("containers");
    let all_containers_info = fs::read_dir(containers_path)?
        .map(|res| res.map(|e| e.file_name()))
        .filter_map(|p| p.ok())
        .map(|f|f.to_string_lossy().to_string())
        .filter_map(|s|get_container_info(s.as_str()).ok())
        .collect::<Vec<ContainerInfo>>();
    Ok(all_containers_info)
}

/// 读取所有容器的状态
fn show_containers(is_show_all: bool) -> Result<()> {
    println!("{:<10} {:<8} {:<10} {:<20} {:<20} {:<20} {:<10}", "id", "pid", "image", "run", "volume", "env", "status");
    for container_info in get_all_container_info()? {
        if is_show_all{
            println!("{container_info}");
        } else if container_info.status == ContainerStatus::RUNNING {
            println!("{container_info}");
        }
    }
    Ok(())
}

fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> { 
    let containers_path = Path::new(WORKSPACE).join("containers");   
    if containers_id == "all" {
        for container_info in get_all_container_info()?{
            stop_container(container_info.id.as_str(), is_remove)?
        }
        // 
        return Ok(())
    }
    for container_id in containers_id.split(" ") {
        let container_work_path = containers_path.join(container_id);
        let container_merged_path = container_work_path.join("merged");
        if let Ok(container_info) = get_container_info(container_id) {
            // 正在运行中的需要 kill
            if container_info.status == ContainerStatus::RUNNING {
                let _ = kill(Pid::from_raw(container_info.pid), Signal::SIGKILL);
                let pid_path = Path::new("/proc").join(container_info.pid.to_string());
                while pid_path.exists() {
                    std::thread::sleep(std::time::Duration::from_millis(10));
                }
            }
            // 卸载自定义挂载点
            if container_info.volume != "" {
                container_info.volume
                    .split(",")
                    .filter_map(|v| v.split(":").last())
                    .map(|v| {
                        if v.starts_with("/") {
                            container_merged_path.join(&v[1..]).to_string_lossy().to_string()
                        } else {
                            container_merged_path.join(v).to_string_lossy().to_string()
                        }
                    })
                    .for_each(|s| {
                        match umount2(s.as_str(), MntFlags::MNT_DETACH) {
                            Ok(_) => println!("卸载自定卷{s}"),
                            Err(e) => println!("卸载卷{s}失败: {e:?}"),
                        }
                    });
            }
            // 卸载overlayfs
            match umount2(container_merged_path.to_str().unwrap(), MntFlags::MNT_DETACH) {
                Ok(_) => println!("卸载overlayfs卷: {container_merged_path:?}"),
                Err(e) => println!("卸载overlayfs失败: {e:?}"),
            }

            println!("停止容器: {container_id:?}");
            // 删除容器目录
            if is_remove {
                match fs::remove_dir_all(container_work_path) {
                    Ok(_) => println!("🟢 删除容器 {container_id} 成功"),
                    Err(e) => println!("🔴 删除容器失败: {e:?}"),
                }
            }
        } else {
            println!("容器不存在: {container_id}, 强制删除");
            // todo 需要强制删除一下目录
            match fs::remove_dir_all(&container_work_path) {
                Ok(_) => println!("强制删除 {container_work_path:?} 成功"),
                Err(e) => println!("强制删除失败: {e:?}"),
            }
        }

        // 容器网络删除
        remove_network(container_id);
    }
    Ok(())
}


fn main() -> Result<()>{
    println!("{LOGO}");
    START_T.get_or_init(|| {
        time::Instant::now()
    });

    let mut args = RockerArgs::parse();
    if args.image.is_some()  || args.restart.is_some() {
        let container_info = match (&args.run, &args.image, &args.restart) {
            (Some(cmd), Some(image), None) => {
                ContainerInfo {
                    id: uuid::Uuid::new_v4().to_string()[0..8].to_string(),
                    pid: -1,
                    run: cmd.clone(),
                    image: image.clone(),
                    volume: args.volume.clone().unwrap_or_default(),
                    env: args.env.clone().unwrap_or_default(),
                    status: ContainerStatus::READY,
                    log: args.log,
                    wait: args.wait
                }
            }
            (None, None, Some(_container_id)) => {
                stop_container(_container_id, false)?;
                get_container_info(_container_id)?
            }
            _ => {
                unreachable!()
            }
        };

        match run_container(&container_info, None) {
            Ok(_) => {
                if container_info.wait {
                    println!("🟢 容器 {} 运行完毕", container_info.id);
                } else {
                    println!("🟢 主进程退出");
                }
                remove_network(&container_info.id);
            }
            Err(e) => {
                // clone 之后的错误 这里已经无法捕获了
                // clone 之前出错, 清理工作目录
                println!("🔴 run_container失败: {e}");
                let is_remove = args.restart.is_none();
                stop_container(&container_info.id, is_remove)?;
            }
        }
    }
    else if args.ps || args.psa {
        // --ps
        show_containers(args.psa)?
    } else if let Some(containers_id) = &args.rm {
        // --rm
        stop_container(containers_id, true)?;
    } else if let Some(containers_id) = &args.stop {
        // --stop
        stop_container(containers_id, false)?;
    } else if let (Some(cmd), Some(container_id)) = (&args.run, &args.exec) {
        // --exec
        let container_info = get_container_info(container_id).unwrap();
        if container_info.status == ContainerStatus::RUNNING {
            run_container(&container_info, Some(cmd)).unwrap();
        } else {
            println!("容器{container_id}未运行");
        }
    }

    Ok(())
}