use flate2::read::GzDecoder;
use std::env;
use std::io::{Cursor, Read, Seek};
use std::path::{Components, Path, PathBuf};
use tar::Archive;

use crate::https;
use crate::system_dirs::get_local_data_directory;
use crate::util;

fn check_java(version: u8) -> bool {
    let dir = get_local_data_directory().join("java").join(format!(
        "java-{}-{}",
        version,
        if env::consts::OS == "windows" {
            "win"
        } else {
            "lin"
        }
    ));
    dir.exists()
}

pub async fn install_java(version: u8, window: tauri::AppHandle) {
    if check_java(version) {
        return;
    }
    //let ftp_dir = PathBuf::new().join("java").join(format!("java-{}-{}", version, if env::consts::OS == "windows" { "win.zip" } else {"lin.tar.gz"}));
    let mut buff = Cursor::new(vec![]);
    //ftp::ftp_retr(Some(window), ftp_dir, &mut buff, |window, data, size| util::download_callback(format!("Java {}", version), window,data, size)).unwrap();
    https::download(
        Some(window.clone()),
        format!(
            "https://gitea.piwalker.net/fclauncher/java/java-{}-{}",
            version,
            if env::consts::OS == "windows" {
                "win.zip"
            } else {
                "lin.tar.gz"
            }
        ),
        &mut buff,
        format!("Java {}", version),
    )
    .await;
    std::fs::create_dir_all(get_local_data_directory().join("java").join(format!(
        "java-{}-{}",
        version,
        if env::consts::OS == "windows" {
            "win"
        } else {
            "lin"
        }
    )))
    .unwrap();
    buff.rewind().unwrap();
    if env::consts::OS != "windows" {
        let tar = GzDecoder::new(buff);
        let mut archive = Archive::new(tar);
        if !unpack_archive(
            archive,
            get_local_data_directory()
                .join("java")
                .join(format!("java-{}-lin", version)),
        )
        .is_ok()
        {
            std::fs::remove_dir_all(
                get_local_data_directory()
                    .join("java")
                    .join(format!("java-{}-lin", version)),
            )
            .unwrap();
        }
    } else {
        if !zip_extract::extract(
            buff,
            get_local_data_directory()
                .join("java")
                .join(format!("java-{}-win", version))
                .as_path(),
            true,
        )
        .is_ok()
        {
            std::fs::remove_dir_all(
                get_local_data_directory()
                    .join("java")
                    .join(format!("java-{}-win", version)),
            )
            .unwrap();
        }
    }
}

fn unpack_archive<T: Read>(
    mut archive: Archive<T>,
    dst: PathBuf,
) -> Result<(), Box<dyn std::error::Error>> {
    for file in archive.entries()? {
        let path = PathBuf::new().join(dst.clone());
        let mut file = file?;
        let file_path = file.path()?;
        let mut file_path = file_path.components();
        let _ = file_path.next();
        let file_path = file_path.as_path();
        file.unpack(path.join(file_path))?;
    }
    Ok(())
}
