use core::io::ErrorKind;
use alloc::{borrow::ToOwned, boxed::Box, collections::btree_map::BTreeMap, string::{String, ToString}, vec::Vec};
use crate::{ffi::{OsStr, OsString}, io::Error, path::{Path, PathBuf}, sync::{Mutex, MutexGuard}};
static ARGS: Mutex<Vec<Box<str>>> = Mutex::new(Vec::new());
static VARS: Mutex<BTreeMap<Box<str>, Box<str>>> = Mutex::new(BTreeMap::new());
pub fn args() -> impl Iterator<Item = String> {
ARGS.lock().expect("args lock poisoned").iter().map(|x| x.to_string()).collect::<Vec<_>>().into_iter()
}
pub fn args_os() -> impl Iterator<Item = OsString> {
args().map(OsString::from)
}
pub fn current_dir() -> Result<PathBuf, Error> {
Ok(PathBuf::from(OsString::from(var("PWD").unwrap_or("/".to_owned()))))
}
pub fn set_current_dir(path: impl AsRef<Path>) -> Result<(), Error> {
unsafe { set_var("PWD", path.as_ref()) };
Ok(())
}
pub fn current_exe() -> Result<PathBuf, Error> {
Ok(Path::new(&args().next().ok_or(Error::from(ErrorKind::NotFound))?).to_owned())
}
pub fn home_dir() -> Option<PathBuf> {
Some(PathBuf::from(OsString::from(var("HOME")?)))
}
pub fn temp_dir() -> PathBuf {
var("TMPDIR").map(|x| PathBuf::from(OsString::from(x))).unwrap_or_else(|| Path::new("/tmp").to_owned())
}
pub fn var(name: impl AsRef<OsStr>) -> Option<String> {
VARS.lock().expect("vars lock poisoned").get(name.as_ref().as_str())
.map(|x| x.to_string())
}
pub fn var_os(name: impl AsRef<OsStr>) -> Option<OsString> {
var(name).map(OsString::from)
}
pub fn vars() -> impl Iterator<Item = (String, String)> {
VARS.lock().expect("vars lock poisoned").iter().map(|(k, v)| (k.to_string(), v.to_string())).collect::<Vec<_>>().into_iter()
}
pub fn vars_os() -> impl Iterator<Item = (OsString, OsString)> {
vars().map(|(a, b)| (OsString::from(a), OsString::from(b)))
}
pub unsafe fn set_var(key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) {
VARS.lock().expect("vars lock poisoned").insert(key.as_ref().as_str().to_owned().into_boxed_str(), value.as_ref().as_str().to_owned().into_boxed_str());
}
pub(crate) fn arg_lock() -> MutexGuard<'static, Vec<Box<str>>> {
ARGS.lock().expect("failed to lock args")
}
pub(crate) fn var_lock() -> MutexGuard<'static, BTreeMap<Box<str>, Box<str>>> {
VARS.lock().expect("failed to lock vars")
}