use crate::Settings;
use anyhow::Result;
use larian_formats::lspk::Lspk;
use std::{fs::OpenOptions, io::Write, path::Path};

impl Settings {
    pub(crate) fn install_all_inner(
        &self,
        verbose: bool,
        dry_run: bool,
        refresh: bool,
        mod_file_paths: Vec<impl AsRef<Path>>,
    ) -> Result<()> {
        mod_file_paths.into_iter().try_for_each(|mod_file_path| {
            let mod_file_path = mod_file_path.as_ref().display().to_string();

            println!("Installing {mod_file_path}");

            self.install(verbose, dry_run, refresh, mod_file_path)
        })
    }

    fn install(
        &self,
        verbose: bool,
        dry_run: bool,
        refresh: bool,
        mut mod_file_path: String,
    ) -> Result<()> {
        if mod_file_path.starts_with('~') {
            let home_dir = std::env::var("HOME")?;
            mod_file_path = mod_file_path.replacen('~', &home_dir, 1);
        }

        let lspk = Lspk::from_file(mod_file_path)?;
        let mod_info = lspk.deserialize_meta_lsx()?.module_info;

        let mut load_order = self.get_load_order()?;

        let existing_entry = load_order.entry(&mod_info.uuid);

        match existing_entry.get() {
            Some(existing) if existing.version > mod_info.version => {
                println!("    {} version {} is already installed", existing.version, mod_info.name);
                println!(
                    "    The mod file you're trying to install is version {}, which is older.",
                    mod_info.version
                );
                println!("    \nNo installation needed!\n");

                return Ok(());
            }
            Some(existing) if existing.version == mod_info.version && !refresh => {
                println!("    {} version {} is already installed", mod_info.name, existing.version);
                println!("    The mod file you're trying to install is the same version");
                println!("\n    No installation needed!\n");

                return Ok(());
            }
            Some(existing) => {
                if verbose {
                    println!(
                        "    updating {} from {} to {}",
                        mod_info.name, existing.version, mod_info.version
                    );
                }
            }
            None => {
                if verbose {
                    println!("    installing {} version {}", mod_info.name, mod_info.version);
                }
            }
        }

        let lspk_installation_path = self.get_mod_file_path(format!("{}.pak", mod_info.folder));

        if !dry_run {
            let mut file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(&lspk_installation_path)?;

            file.write_all(&lspk.packed_bytes)?;
        }

        existing_entry.update(mod_info);

        if dry_run {
            print!("    non-dry run would have ");
        } else {
            todo!()
            // self.write_settings_file(&load_order)?;
        }

        println!("    installed {}\n", lspk_installation_path.display());

        Ok(())
    }
}
