use std::{io, fs, fmt, path};
use fmt::{Display, Formatter};
use io::{Read, Write};
use path::Path;
use rand::Rng;

static NETWORK_FILE: &str = "/home/rocker/network";


#[derive(Debug, Clone)]
struct NetWrok {
    gateway_addr: String,       // 192.168.124.0
    bridge_addr: String,        // 192.168.124.1
    slave_addr: String,

    bridge_name: String,       // ro_uuid[:8]_1  // ip 就是 192.168.124.1
    master_veth_name: String,  // ro_uuid[:8]_2  // 不分配ip 直接插到桥
    slave_veth_name: String,   // ro_uuid[:8]_3  // ip 就是 192.168.124.3, 插在容器中
}


impl Display for NetWrok {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{},{},{},{},{},{}", self.gateway_addr, self.bridge_addr, self.slave_addr, self.bridge_name, self.master_veth_name, self.slave_veth_name)
    }
}


fn set_snat(gateway_addr: &str, bridge_name: &str, action: &str) -> bool {
    // 检查是否存在 iptables -t nat -L POSTROUTING -n
    let args = ["-t", "nat", "-L", "POSTROUTING", "-n"];
    let out = std::process::Command::new("iptables")
        .args(args)
        .output()
        .unwrap();

    let is_some = String::from_utf8_lossy(&out.stdout).contains(gateway_addr);
    if is_some && action == "-A" {
        println!("snat 已经存在, 无法再次创建");
        return false;
    } else if is_some == false && action == "-D" {
        println!("snat 本身不存在,不需要删除");
        return true;
    }

    // sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/24 ! -o br0 -j MASQUERADE
    let args = ["-t", "nat", action, "POSTROUTING", "-s", &format!("{gateway_addr}/24"), "!", "-o", bridge_name, "-j", "MASQUERADE"];
    let out = std::process::Command::new("iptables")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_snat: {args:?}");
        println!("{:?}", out);
        return false;
    }
    true
}

fn take_all_network() -> Vec<NetWrok> {
    // 打开 NETWORK_FILE 所有已经配置的信息, 如果没有则创建
    let network_file_paht = Path::new(NETWORK_FILE);
    if (0..100).any(|i| {
        std::thread::sleep(std::time::Duration::from_millis(i));
        network_file_paht.exists()
    }) == false {
        println!("🔴 网络设备逻辑锁获取失败");
    };

    let mut f = fs::OpenOptions::new()
        .write(true)
        .read(true)
        .open(NETWORK_FILE)
        .unwrap();
    let mut text = String::new();
    f.read_to_string(&mut text).unwrap();

    // 逻辑锁, 删除 NETWORK_FILE文件, 由外部修改后更新算了, 暂时这么设计
    let _ = fs::remove_file(NETWORK_FILE);

    let mut all_network = vec![];
    for line in text.lines() {
        let network_info_vec = line.split(",").collect::<Vec<&str>>();
        all_network.push(NetWrok {
            gateway_addr: network_info_vec[0].to_string(),
            bridge_addr: network_info_vec[1].to_string(),
            slave_addr: network_info_vec[2].to_string(),
            bridge_name: network_info_vec[3].to_string(),
            master_veth_name: network_info_vec[4].to_string(),
            slave_veth_name: network_info_vec[5].to_string(),
        })
    }

    all_network
}


fn write_network_info(all_network: Vec<NetWrok>) {
    let mut f = fs::OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(NETWORK_FILE)
        .unwrap();
    for n in all_network {
        writeln!(f, "{}", n).unwrap();
    }
}

fn del_dev(dev_name: &str) -> bool {
    // 先检查是否还有该设备
    let args = ["link", "show", dev_name];
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();

    if out.status.success() {
        // 下线
        let args = ["link", "set", dev_name, "down"];
        let _ = std::process::Command::new("ip")
            .args(args)
            .output()
            .unwrap();

        // ip link delete dev_name
        let args = ["link", "delete", dev_name];
        let out = std::process::Command::new("ip")
            .args(args)
            .output()
            .unwrap();
        if !out.status.success() {
            println!("del_dev: {args:?}");
            println!("{:?}", out);
            return false;
        }
    }
    true
}


pub fn remove_network(uuid_name: &str) {
    let mut all_network = take_all_network();
    let mut network = None;
    all_network = all_network.into_iter()
        .filter_map(|n| {
            if n.bridge_name.contains(uuid_name) {
                network = Some(n);
                None
            } else {
                Some(n)
            }
    }).collect::<Vec<NetWrok>>();

    if let Some(network) = network {
        del_dev(&network.bridge_name);
        del_dev(&network.master_veth_name);
        set_snat(&network.gateway_addr, &network.bridge_name, "-D");
    }
    // 回写到文件中
    write_network_info(all_network);
    println!("删除网络设备: {uuid_name}");
}


pub fn create_network(uuid_name: &str, pid: i32) -> bool {
    let pid = pid.to_string();
    let bridge_name = format!("ro_{uuid_name}_1");
    let master_veth_name = format!("ro_{uuid_name}_2");
    let slave_veth_name = format!("ro_{uuid_name}_3");

    // 创建一个随机地址段的 没分配过的ip
    let mut all_network = take_all_network();

    if all_network.iter().any(|n|n.bridge_name == bridge_name) {
        println!("{uuid_name} 已经存在一个网卡, 无法再次创建");
        return false;
    }

    let mut rg = rand::thread_rng();

    let network = loop {
        // 生成一个随机桥ip
        let base_addr = format!("10.{}.{}", rg.gen_range(1..255), rg.gen_range(1..255));
        let gateway_addr = format!("{base_addr}.0");
        let bridge_addr = format!("{base_addr}.1");
        let slave_addr = format!("{base_addr}.3");

        if all_network.iter().any(|n|n.bridge_addr == bridge_addr) == false {
            let net_work = NetWrok {
                gateway_addr,
                bridge_addr,
                slave_addr,
                bridge_name,
                master_veth_name,
                slave_veth_name,
            };
            break net_work;
        }
    };

    all_network.push(network.clone());
    // 写入到文件中
    write_network_info(all_network);

    let bridge_addr_24 =  &format!("{}/24", &network.bridge_addr);
    let slave_addr_24 = &format!("{}/24", &network.slave_addr);
    let cmd_lis = vec![
        vec!["brctl", "addbr", &network.bridge_name],
        vec!["ip", "addr", "add", bridge_addr_24, "dev", &network.bridge_name],
        vec!["ip", "link", "add", &network.master_veth_name, "type", "veth", "peer", "name", &network.slave_veth_name],
        vec!["brctl", "addif", &network.bridge_name, &network.master_veth_name],
        vec!["ip", "link", "set", &network.slave_veth_name, "netns", &pid],
        vec!["nsenter", "-t", &pid, "-n", "--", "ip", "addr", "add", slave_addr_24, "dev", &network.slave_veth_name],
        vec!["ip", "link", "set", &network.bridge_name, "up"],
        vec!["ip", "link", "set", &network.master_veth_name, "up"],
        vec!["nsenter", "-t", &pid, "-n", "--", "ip", "link", "set", "dev", &network.slave_veth_name, "up"],
        vec!["nsenter", "-t", &pid, "-n", "--", "ip", "link", "set", "lo", "up"],
        vec!["nsenter", "-t", &pid, "-n", "--", "ip", "route", "add", "default", "via", &network.bridge_addr, "dev", &network.slave_veth_name],
        vec!["sysctl", "net.ipv4.conf.all.forwarding=1"],
        vec!["iptables", "-t", "filter", "-P", "FORWARD", "ACCEPT"],
    ];

    let mut f = true;
    for cmd in cmd_lis {
        let out = std::process::Command::new(cmd[0])
            .args(&cmd[1..])
            .output()
            .unwrap();
        if !out.status.success() {
            println!("{:?}", cmd);
            println!("{:?}", out);
            f = false;
            break;
        }
    }
    if f && set_snat(&network.gateway_addr, &network.bridge_name, "-A") {
        println!("🟢 网络设备创建成功");
        true
    } else {
        println!("🔴 网络设备创建失败");
        remove_network(&uuid_name);
        false
    }
}

fn main(){
    let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string();
    // create_network(&container_id, 2084);
    // remove_network("c3a20664");
}




