use crate::base::{
    println_tabled, read_input, read_input_or_default, to_auth_type, AuthType,
    MmhConfig, ServiceConfig, ServiceConfigView, ServicePingView,
};
use crate::{get_config, get_config_path};
use std::io::Write;
use std::net::{TcpStream, ToSocketAddrs};
use std::os::unix::prelude::CommandExt;
use std::{fs, io};

pub fn list() {
    let mut data_vec: Vec<ServiceConfigView> = vec![];
    for (i, s) in get_config().servers.iter().enumerate() {
        let t_s = s.clone();
        data_vec.push(ServiceConfigView {
            id: i,
            name: t_s.name,
            host: t_s.host,
            port: t_s.port,
            user: t_s.user,
            auth_type: t_s.auth_type.as_str().to_string(),
        })
    }
    println_tabled(data_vec);
}

pub fn add() {
    let name = read_input("请输入服务器名称:");
    let host = read_input("请输入服务器地址:");
    let port = read_input("请输入服务器端口:").parse::<u16>().unwrap();
    let user = read_input("请输入服务器用户名:");
    let auth_type_str = read_input("请输入服务器认证方式(pwd,secret):")
        .parse::<String>()
        .unwrap();
    let mut password = String::new();
    let mut key_file = String::new();
    let auth_type = to_auth_type(auth_type_str.as_str());
    match auth_type {
        AuthType::Pwd => {
            password = read_input("请输入服务器密码:");
        }
        AuthType::Secret => {
            key_file = read_input("请输入服务器密钥文件:");
        }
    }
    let service_config = ServiceConfig {
        name,
        host,
        port,
        user,
        auth_type,
        password,
        key_file,
    };

    let config_str = fs::read_to_string(get_config_path()).unwrap_or_default();

    if config_str.is_empty() {
        let mmh_config = MmhConfig {
            servers: vec![service_config],
            sync_cmd: None,
        };
        let toml_value = toml::to_string(&mmh_config).unwrap();
        fs::File::create(get_config_path())
            .expect("无法创建文件")
            .write_all(toml_value.as_bytes())
            .expect("无法写入文件");
    } else {
        let mut config = get_config();
        config.servers.push(service_config);
        let toml_value = toml::to_string(&config).unwrap();
        fs::File::create(get_config_path())
            .expect("无法创建文件")
            .write_all(toml_value.as_bytes())
            .expect("无法写入文件");
    }
}

pub fn remove(name_option: Option<&String>) {
    let config = get_config();

    match name_option {
        Some(name) => {
            for (i, s) in config.servers.iter().enumerate() {
                if s.name.eq(name) {
                    let mut new_config = config.clone();
                    new_config.servers.remove(i);
                    remove_save(new_config);
                }
            }
        }
        None => {
            list();
            let id = read_input("请输入要删除的服务器序号:")
                .parse::<usize>()
                .expect("请输入数字");
            let mut new_config = config.clone();
            new_config.servers.remove(id);
            remove_save(new_config);
        }
    }
}

pub fn sftp(name_option: Option<&String>, remote_dir: Option<&String>) {
    let config = get_config();
    match name_option {
        Some(name) => {
            for s in config.servers {
                if s.name.eq(name) {
                    sftp_connect(s.clone(), remote_dir)
                }
            }
        }
        None => {
            list();
            let id = read_input("请输入要链接的服务器序号:")
                .parse::<usize>()
                .expect("请输入数字");
            let current_config = config.servers[id].clone();
            sftp_connect(current_config.clone(), remote_dir)
        }
    }
}

pub fn ping() {
    let config = get_config();
    let mut data_vec: Vec<ServicePingView> = vec![];
    for (i, s) in config.servers.iter().enumerate() {
        let t_s = s.clone();
        let mut flag = false;
        match test_tcp_connection(s.host.as_str(), s.port) {
            Ok(ping_result) => {
                flag = ping_result;
            }
            _ => {}
        }

        data_vec.push(ServicePingView {
            id: i,
            name: t_s.name,
            host: t_s.host,
            port: t_s.port,
            ping_result: flag,
        });
    }
    println_tabled(data_vec)
}


pub fn connect(name_option: Option<&String>) {
    let config = get_config();
    match name_option {
        Some(name) => {
            for s in config.servers {
                if s.name.eq(name) {
                    ssh_connect(s.clone())
                }
            }
        }
        None => {
            list();
            let id = read_input("请输入要登录的服务器序号:")
                .parse::<usize>()
                .expect("请输入数字");
            let current_config = config.servers[id].clone();
            ssh_connect(current_config.clone())
        }
    }
}

fn ssh_connect(s: ServiceConfig) {
    println!("connect to {}  mode!", s.name);
    match s.auth_type {
        AuthType::Pwd => {
            // sshpass -p xxx ssh user@host -p port
            let _ = std::process::Command::new("sshpass")
                .arg("-p")
                .arg(s.password)
                .arg("ssh")
                .arg("-o")
                .arg("StrictHostKeyChecking=no")
                .arg(format!("{}@{}", s.user, s.host))
                .arg("-p")
                .arg(s.port.to_string())
                .exec();
        }
        AuthType::Secret => {
            // ssh -i key_file user@host -p port
            let _ = std::process::Command::new("ssh")
                .arg("-i")
                .arg(s.key_file)
                .arg("-o")
                .arg("StrictHostKeyChecking=no")
                .arg(format!("{}@{}", s.user, s.host))
                .arg("-p")
                .arg(s.port.to_string())
                .exec();
        }
    }
}

fn remove_save(config: MmhConfig) {
    let mmh_config = MmhConfig {
        servers: config.servers,
        sync_cmd: config.sync_cmd,
    };
    let toml_value = toml::to_string(&mmh_config).unwrap();
    fs::File::create(get_config_path())
        .expect("无法创建文件")
        .write_all(toml_value.as_bytes())
        .expect("无法写入文件");
}

fn sftp_connect(s: ServiceConfig, remote_dir: Option<&String>) {
    println!("connect to {} !", s.name);
    match s.auth_type {
        AuthType::Pwd => {
            // sshpass -p xxx  sftp user@host:remoteDir -p port
            let _ = std::process::Command::new("sshpass")
                .arg("-p")
                .arg(s.password)
                .arg("sftp")
                .arg("-o")
                .arg("StrictHostKeyChecking=no")
                .arg("-P")
                .arg(s.port.to_string())
                .arg(format!(
                    "{}@{}:{}",
                    s.user,
                    s.host,
                    remote_dir.unwrap_or(&".".to_string())
                ))
                .exec();
        }
        AuthType::Secret => {
            // sftp -i key_file user@host:remoteDir -p port
            let _ = std::process::Command::new("sftp")
                .arg("-i")
                .arg(s.key_file)
                .arg("-o")
                .arg("StrictHostKeyChecking=no")
                .arg("-p")
                .arg(s.port.to_string())
                .arg(format!(
                    "{}@{}:{}",
                    s.user,
                    s.host,
                    remote_dir.unwrap_or(&".".to_string())
                ))
                .exec();
        }
    }
}

fn test_tcp_connection(ip: &str, port: u16) -> Result<bool, io::Error> {
    let address = format!("{}:{}", ip, port)
        .to_socket_addrs()?
        .next()
        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Failed to parse address"))?;

    match TcpStream::connect_timeout(&address, std::time::Duration::from_secs(5)) {
        Ok(_) => Ok(true), // 端口开放
        Err(ref e) if e.kind() == io::ErrorKind::ConnectionRefused => Ok(false), // 端口关闭
        Err(e) => Err(e),  // 其他错误
    }
}

pub fn copy_server_config(name_option: Option<&String>) {
    let config = get_config();
    match name_option {
        Some(name) => {
            for s in config.servers {
                if s.name.eq(name) {
                    copy_server(s.clone())
                }
            }
        }
        None => {
            list();
            let id = read_input("请输入要复制的服务器序号:")
                .parse::<usize>()
                .expect("请输入数字");
            let current_config = config.servers[id].clone();
            copy_server(current_config.clone())
        }
    }
}

fn copy_server(service_config: ServiceConfig) {
    let name = read_input(&format!("请输入服务器新名称({}):", service_config.name));
    let host = read_input(&format!("请输入服务器地址:({})", service_config.host));
    let port = read_input(&format!("请输入服务器端口({}):", service_config.port))
        .parse::<u16>()
        .unwrap_or(service_config.port);
    let user = read_input(&format!("请输入服务器用户名({}):", service_config.user));
    let auth_type_str = read_input_or_default(
        &format!(
            "请输入服务器认证方式(pwd,secret)({}):",
            service_config.auth_type.as_str()
        ),
        service_config.auth_type.as_str(),
    );
    let mut password = String::new();
    let mut key_file = String::new();
    let auth_type = to_auth_type(auth_type_str.as_str());
    match auth_type {
        AuthType::Pwd => {
            password = read_input(&format!("请输入服务器密码({}):", service_config.password));
        }
        AuthType::Secret => {
            key_file = read_input(&format!(
                "请输入服务器密钥文件({}):",
                service_config.key_file
            ));
        }
    }

    let new_name = if name.is_empty() {
        service_config.name
    } else {
        name
    };
    let new_host = if host.is_empty() {
        service_config.host
    } else {
        host
    };
    let new_port = if port == 0 { service_config.port } else { port };
    let new_user = if user.is_empty() {
        service_config.user
    } else {
        user
    };
    let new_auth_type = if auth_type_str.is_empty() {
        service_config.auth_type
    } else {
        to_auth_type(auth_type_str.as_str())
    };
    let new_password = if password.is_empty() {
        service_config.password
    } else {
        password
    };
    let new_key_file = if key_file.is_empty() {
        service_config.key_file
    } else {
        key_file
    };
    let new_service_config = ServiceConfig {
        name: new_name,
        host: new_host,
        port: new_port,
        user: new_user,
        auth_type: new_auth_type,
        password: new_password,
        key_file: new_key_file,
    };

    //必然存在配置
    let mut config = get_config();
    config.servers.push(new_service_config);
    let toml_value = toml::to_string(&config).unwrap();
    fs::File::create(get_config_path())
        .expect("无法创建文件")
        .write_all(toml_value.as_bytes())
        .expect("无法写入文件");
}