use std::path::{Path, PathBuf};
use std::process::{Command, Output};

use anyhow::{Context, Result};
use tempfile::TempDir;

/// Isolated environment for running the `pijul` CLI in tests.
///
/// This prevents tests from reading/writing the developer machine's config under
/// `$HOME` / `XDG_CONFIG_HOME` / `XDG_DATA_HOME`.
pub struct PijulEnv {
    temp_dir: TempDir,
}

impl PijulEnv {
    pub fn new() -> Result<Self> {
        Ok(Self {
            temp_dir: TempDir::new().context("failed to create temp dir for PijulEnv")?,
        })
    }

    pub fn home_dir(&self) -> &Path {
        self.temp_dir.path()
    }

    pub fn xdg_config_home(&self) -> PathBuf {
        self.temp_dir.path().join(".config")
    }

    pub fn xdg_data_home(&self) -> PathBuf {
        self.temp_dir.path().join(".local").join("share")
    }

    pub fn apply_env(&self, cmd: &mut Command) {
        cmd.env("HOME", self.home_dir())
            .env("XDG_CONFIG_HOME", self.xdg_config_home())
            .env("XDG_DATA_HOME", self.xdg_data_home());
    }
}

pub fn run_pijul(mut cmd: Command) -> Result<Output> {
    let output = cmd.output().context("failed to spawn pijul")?;
    anyhow::ensure!(
        output.status.success(),
        "pijul exited with {}.\nstdout:\n{}\nstderr:\n{}",
        output.status,
        String::from_utf8_lossy(&output.stdout),
        String::from_utf8_lossy(&output.stderr)
    );
    Ok(output)
}