//
// Syd: rock-solid application kernel
// src/syd-env.rs: Run a command with the environment of the process with the given PID.
//
// Copyright (c) 2024 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use std::{
    collections::VecDeque,
    os::unix::process::CommandExt,
    process::{exit, Command, ExitCode, Stdio},
    time::Duration,
};

use nix::libc::pid_t;
#[allow(clippy::disallowed_types)]
use procfs::process::Process;
use syd::{err::SydResult, syslog::LogLevel, wordexp::WordExp};

fn main() -> SydResult<ExitCode> {
    syd::set_sigpipe_dfl()?;

    // Initialize logging.
    syd::log::log_init_simple(LogLevel::Warn)?;

    let mut args: VecDeque<_> = std::env::args().skip(1).collect();
    let pid: pid_t = match args.pop_front().as_deref() {
        None | Some("-h") => {
            help();
            return Ok(ExitCode::SUCCESS);
        }
        Some("-e") => {
            let var = if let Some(var) = args.pop_front() {
                var
            } else {
                eprintln!("Error: -e requires an argument!");
                return Ok(ExitCode::FAILURE);
            };
            match WordExp::expand(&var, true, Duration::from_secs(3)) {
                Ok(val) => {
                    print!("{val}");
                    return Ok(ExitCode::SUCCESS);
                }
                Err(err) => {
                    eprintln!("Error: {err}");
                    exit(err.into());
                }
            };
        }
        Some(pid) => match pid.parse() {
            Ok(pid) => pid,
            Err(error) => {
                eprintln!("Invalid PID: {error}");
                return Ok(ExitCode::FAILURE);
            }
        },
    };

    #[allow(clippy::disallowed_types)]
    let proc = match Process::new(pid) {
        Ok(proc) => proc,
        Err(error) => {
            eprintln!("syd-env: {error}");
            return Ok(ExitCode::FAILURE);
        }
    };

    let environ = match proc.environ() {
        Ok(environ) => environ,
        Err(error) => {
            eprintln!("syd-env: {error}");
            return Ok(ExitCode::FAILURE);
        }
    };

    let error = Command::new("env")
        .args(args)
        .env_clear()
        .envs(&environ)
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .exec();
    eprintln!("syd-env: {error}");
    Ok(ExitCode::FAILURE)
}

fn help() {
    println!("Usage: syd-env pid [-i] [name=value]... {{command [arg...]}}");
    println!("Run a command with the environment of the process with the given PID.");
}
