#![cfg(test)]

use once_cell::sync::Lazy;
use std::env;
use std::ffi::OsString;
use std::sync::{Mutex, MutexGuard};

static ENV_GUARD: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));

pub(crate) struct EnvLock {
    saved: Vec<(OsString, Option<OsString>)>,
    _guard: MutexGuard<'static, ()>,
}

impl EnvLock {
    pub(crate) fn acquire(vars: &[&str]) -> Self {
        let guard = ENV_GUARD.lock().unwrap_or_else(|e| e.into_inner());
        let saved = vars
            .iter()
            .map(|key| (OsString::from(key), env::var_os(key)))
            .collect();
        Self {
            saved,
            _guard: guard,
        }
    }

    pub(crate) fn set_var(&self, key: &str, value: &str) {
        unsafe { env::set_var(key, value) };
    }

    pub(crate) fn remove_var(&self, key: &str) {
        unsafe { env::remove_var(key) };
    }
}

impl Drop for EnvLock {
    fn drop(&mut self) {
        for (key, value) in &self.saved {
            unsafe {
                if let Some(val) = value {
                    env::set_var(key, val);
                } else {
                    env::remove_var(key);
                }
            }
        }
    }
}
