#![allow(unused)]
use std::{
    collections::HashMap,
    fmt::format,
    fs::{read_to_string, File},
    io::{BufWriter, Write},
    process::exit,
};

use {error_stack::Report, hblang::Options};

use crate::Error;
pub struct Package {
    name:      String,
    binaries:  Vec<String>,
    build_cmd: String,
    args:      HashMap<String, String>,
}

impl Package {
    pub fn load_from_file(path: String) -> Self {
        let contents = match std::fs::read_to_string(path.clone()) {
            // If successful return the files text as `contents`.
            // `c` is a local variable.
            Ok(c) => c,
            // Handle the `error` case.
            Err(_) => {
                // Write `msg` to `stderr`.
                eprintln!("Could not read file `{}`", path);
                // Exit the program with exit code `1`.
                exit(1);
            }
        };
        use toml::Value;

        let mut data: Value = toml::from_str(&contents).unwrap();
        let mut name = data
            .get("package")
            .unwrap()
            .get("name")
            .unwrap()
            .to_string();
        name.pop();
        name.remove(0);

        let dependants = data.get("dependants").unwrap();
        let bin_table = dependants.get("binaries").unwrap().as_table().unwrap();
        let mut binaries = vec![];

        for (count, (name, table)) in bin_table.into_iter().enumerate() {
            binaries.push(name.clone());
        }
        let build_table = data.get("build").unwrap();

        let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
        build_cmd.remove(0);
        let mut args: HashMap<String, String> = match build_table.get("args") {
            None => HashMap::new(),
            Some(v) => v
                .as_table()
                .unwrap()
                .into_iter()
                .map(|(k, v)| (k.clone(), v.to_string()))
                .collect::<HashMap<String, String>>(),
        };

        Self {
            name,
            binaries,
            build_cmd,
            args,
        }
    }
    pub fn build(&self, out: &mut Vec<u8>) -> std::io::Result<()> {
        if self.binaries.contains(&"hblang".to_string()) {
            let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
            let path = format!("sysdata/programs/{}/{}", self.name, file);
            // compile here

            let mut warnings = String::new();

            hblang::run_compiler(
                &path,
                Options {
                    fmt: true,
                    resolver: Some(hblang::ABLEOS_PATH_RESOLVER),

                    ..Default::default()
                },
                out,
                &mut warnings,
            )?;

            match std::fs::create_dir("target/programs") {
                Ok(_) => (),
                Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
                Err(e) => panic!("{}", e),
            }

            hblang::run_compiler(
                &path,
                Options {
                    resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
                    ..Default::default()
                },
                out,
                &mut warnings,
            )?;
            std::fs::write(format!("target/programs/{}.hbf", self.name), &out)?;
            out.clear();

            hblang::run_compiler(
                &path,
                Options {
                    resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
                    dump_asm: true,

                    ..Default::default()
                },
                out,
                &mut warnings,
            )?;
            std::fs::write(format!("target/programs/{}.hba", self.name), &out)?;
            out.clear();
        }
        Ok(())
    }
}