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

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

fn get_gateway_addr(addr: &str) -> String {
    let prefix = &addr[..addr.len() - 1];
    format!("{}0", prefix)
}
fn create_bridge_dev(bridge_name: &str) -> bool {
    // brctl addbr br0
    let args = ["addbr", bridge_name];
    let out = std::process::Command::new("brctl")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("create_bridge_dev: {args:?}");
        println!("{:?}", out);
        return false
    }
    true
}

fn set_bridge_ip(bridge_name: &str, addr: &str) -> bool {
    // 设置容器内从ip: ip addr add 192.168.124.1/24 dev bridge_name
    let args = ["addr", "add", &format!("{addr}/24"), "dev", bridge_name];
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_bridge_ip: {args:?}");
        println!("{:?}", out);
        return false;
    }
    true
}

fn set_slave_ip(slave_veth_name: &str, addr: &str, pid: &str) -> bool {
    // nsenter -t 10050 -n -- ip addr add <ip_address>/<subnet_mask> dev veth1
    let args = ["-t", pid, "-n", "--", "ip", "addr", "add", &format!("{addr}/24"), "dev", slave_veth_name];
    let out = std::process::Command::new("nsenter")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_slave_ip: {args:?}");
        println!("{:?}", out);
        return false;
    }
    true
}

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 set_iptables_forward() -> bool {
    // sudo sysctl net.ipv4.conf.all.forwarding=1
    let args = ["net.ipv4.conf.all.forwarding=1"];
    let out = std::process::Command::new("sysctl")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_iptables_forward: {args:?}");
        println!("{:?}", out);
        return false;
    }
    // sudo iptables -t filter -P FORWARD ACCEPT
    let args = ["-t", "filter", "-P", "FORWARD", "ACCEPT"];
    let out = std::process::Command::new("iptables")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_iptables_forward: {args:?}");
        println!("{:?}", out);
        return false;
    }
    true
}


fn set_slave_route(slave_veth_name: &str, bridge_addr: &str, pid: &str) -> bool {
    // sudo nsenter -t 1851 -n -- ip route add default via 172.18.0.1 dev veth3
    let args = ["-t", pid, "-n", "--", "ip", "route", "add", "default", "via", bridge_addr, "dev", slave_veth_name];
    let out = std::process::Command::new("nsenter")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_slave_route: {args:?}");
        println!("{:?}", out);
        return false;
    }
    true
}

fn set_net_up(bridge_name: &str, master_veth_name: &str, pid: &str, slave_veth_name: &str) -> bool {
    // sudo ip link set bridge_name up
    let args = ["link", "set", bridge_name, "up"];
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_up: {args:?}");
        println!("{:?}", out);
        return false;
    }

    // sudo ip link set master_veth_name up
    let args = ["link", "set", master_veth_name, "up"];
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_up: {args:?}");
        println!("{:?}", out);
        return false;
    }

    // nsenter -t 1970  -n -- ip link set dev slave_veth_name up
    let args = ["-t", pid, "-n", "--", "ip", "link", "set", "dev", slave_veth_name, "up"];
    let out = std::process::Command::new("nsenter")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_up: {args:?}");
        println!("{:?}", out);
        return false;
    }

    // ip link set lo up
    let args = ["-t", pid, "-n", "--", "ip", "link", "set", "lo", "up"];
    let out = std::process::Command::new("nsenter")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("set_up: {args:?}");
        println!("{:?}", out);
        return false;
    }
    true
}

fn set_up(dev_name: &str) {
    // sudo ip link set bridge_name up
    let args = ["link", "set", dev_name, "up"];
    println!("set_up: {args:?}");
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("{:?}", out);
    }
}

fn set_route(bridge_name: &str, addr: &str) {
    // ip route add 192.168.100.0/24 via 192.168.100.1 dev bridge_name
    // sudo ip netns exec ns1 ip route add default via 172.18.0.1 dev veth0
    // 把addr最后的1位替换为0
    let gateway_addr = get_gateway_addr(addr);

    // 删掉系统自动添加的 ip route del 172.18.0.0/24 dev br0
    let args = ["route", "del", &format!("{gateway_addr}/24"), "dev", bridge_name];
    println!("set_route: {args:?}");
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("{:?}", out);
    }

    let args = ["route", "add", &format!("{gateway_addr}/24"), "via", addr, "dev", bridge_name];
    println!("set_route: {args:?}");
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("{:?}", out);
    }
}

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

fn del_bridge(bridge_name: &str) -> bool {
    // 是否还存在设备
    let args = ["link", "show", bridge_name];
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();

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

        // brctl delbr br0
        let args = ["delbr", bridge_name];
        let out = std::process::Command::new("brctl")
            .args(args)
            .output()
            .unwrap();
        if !out.status.success() {
            println!("del_bridge: {args:?}");
            println!("{:?}", out);
            return false;
        }
    }
    true
}


fn create_veth_pair(master_veth_name: &str, slave_veth_name: &str) -> bool {
    // sudo ip link add master_veth_name type veth peer name slave_veth_name
    let args = ["link", "add", master_veth_name, "type", "veth", "peer", "name", slave_veth_name];
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("create_veth_pair: {args:?}");
        println!("{:?}", out);
        return false;
    }
    return true;
}


#[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 get_all_network() -> Vec<NetWrok> {
    // 打开 NETWORK_FILE 所有已经配置的信息, 如果没有则创建
    let mut f = OpenOptions::new()
        .write(true)
        .create(true)
        .read(true)
        .open(NETWORK_FILE)
        .unwrap();
    let mut text = String::new();
    f.read_to_string(&mut text).unwrap();

    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 master_join_bridge(bridge_name: &str, master_veth_name: &str) -> bool {
    // 将主端链接到桥
    //sudo brctl addif bridge_name master_veth_name
    let args = ["addif", bridge_name, master_veth_name];
    let out = std::process::Command::new("brctl")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("master_join_bridge: {args:?}");
        println!("{:?}", out);
        return false;
    }
    true
}

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

fn slave_join_bridge(slave_veth_name: &str, pid: &str) -> bool {
    // 将从端 链接到容器
    // sudo ip link set slave_veth_name netns 1234
    let args = ["link", "set", slave_veth_name, "netns", pid];
    let out = std::process::Command::new("ip")
        .args(args)
        .output()
        .unwrap();
    if !out.status.success() {
        println!("slave_join_bridge: {args:?}");
        println!("{:?}", out);
        return false;
    }
    true
}

pub fn create_network(uuid_name: &str, pid: i32) -> bool {
    // 创建一个随机地址段的 没分配过的ip
    let mut all_network = get_all_network();
    let mut rg = rand::thread_rng();

    let network = loop {
        // 生成一个随机桥ip
        let base_addr = format!("10.{}.{}", rg.gen_range(0..255), rg.gen_range(0..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 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");
            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);
    
    // 系统中创建桥
    if create_bridge_dev(&network.bridge_name) &&
    // 给桥分配ip
    set_bridge_ip(&network.bridge_name, &network.bridge_addr) &&
    // 创建veth pair
    create_veth_pair(&network.master_veth_name, &network.slave_veth_name) &&
    // 宿主机 主pair 连接桥
    master_join_bridge(&network.bridge_name, &network.master_veth_name) &&
    // 把从 pair 添加到容器内
    slave_join_bridge(&network.slave_veth_name, pid.to_string().as_str()) &&
    // 给容器内 pair 分配ip
    set_slave_ip(&network.slave_veth_name, &network.slave_addr, pid.to_string().as_str()) &&
    // 激活 上线
    set_net_up(&network.bridge_name, &network.master_veth_name, pid.to_string().as_str(), &&network.slave_veth_name) &&
    // 访问公网设置
    // 配置路由
    set_slave_route(&network.slave_veth_name, &network.bridge_addr, pid.to_string().as_str()) &&
    // 设置转发规则
    set_iptables_forward() &&
    // 设置snat
    set_snat(&network.gateway_addr, &network.bridge_name, "-A") {
        println!("网络设备创建完成");
        true
    } else {
        println!("create_network failed");
        remove_network(&uuid_name);
        false
    }
}


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 = get_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);
}

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




