use crate::colors::get_colors;
use crate::config::get_config;
use std::env::set_var;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::path::PathBuf;
use std::process::exit;
use std::process::Command;
use tempfile::Builder;

/// Runs the `.SlackBuild` script for the given package.
///
/// Creates a per-build temporary directory used as the script's `OUTPUT` env
/// variable, sets executable permissions on the script, then runs it via `bash`
/// with stdout and stderr written to the build log file simultaneously. Returns
/// the path to the temporary directory containing the built package.
///
/// # Exits
///
/// Exits with a non-zero code if the script fails or cannot be executed.
pub fn build(pkg_name: &str) -> PathBuf {
    let cfg = get_config();
    let color = get_colors(cfg.colors);
    let log_file = format!("{}/{}", &cfg.var_log_path, &cfg.build_log_file);

    let pkg_build_path = format!("{}{}", cfg.build_path, pkg_name);
    let script = format!("{pkg_build_path}/{pkg_name}.SlackBuild");

    // chmod +x
    let mut perms = fs::metadata(&script)
        .unwrap_or_else(|e| {
            eprintln!("{}Error:{} {}: {}", color.red, color.reset, script, e);
            exit(1);
        })
        .permissions();

    perms.set_mode(0o755);

    fs::set_permissions(&script, perms).unwrap_or_else(|e| {
        eprintln!("{}Error:{} {}: {}", color.red, color.reset, script, e);
        exit(1);
    });

    let output_dir = Builder::new()
        .prefix(&format!("{pkg_name}."))
        .tempdir_in(&cfg.build_path)
        .unwrap_or_else(|e| {
            eprintln!(
                "{}Error:{} failed to create temp dir: {}",
                color.red, color.reset, e
            );
            exit(1);
        })
        .keep();

    set_var("MAKEFLAGS", cfg.makeflags);

    let status = Command::new("bash")
        .arg("-c")
        .arg(format!(
            "set -o pipefail; \"{}\" 2>&1 | tee -a \"{}\"",
            script, &log_file
        ))
        .env("OUTPUT", output_dir.as_path())
        .status()
        .unwrap_or_else(|e| {
            eprintln!(
                "{}Error:{} Failed to run {}: {}",
                color.red, color.reset, script, e
            );
            exit(1);
        });

    if !status.success() {
        eprintln!(
            "\n{}Error:{} Build failed for {}\n",
            color.red, color.reset, pkg_name
        );
        exit(1);
    }
    output_dir
}

/// Truncates the build log file to zero bytes.
///
/// Called once before a batch build so that `build` can append to a fresh log
/// via `tee -a` without mixing output from previous runs.
///
/// # Exits
///
/// Does not exit on failure; emits a warning instead so the build can proceed.
pub fn clear_build_log() {
    let cfg = get_config();
    let color = get_colors(cfg.colors);
    let log_file = format!("{}/{}", cfg.var_log_path, cfg.build_log_file);
    if let Err(e) = fs::write(&log_file, "") {
        eprintln!(
            "{}Warning:{} Cannot write log file {}: {}",
            color.yellow, color.reset, log_file, e
        );
    }
}
