use std::path::{Path, PathBuf};

use sysinfo::{
    System,
    SystemExt,
    Pid,
    PidExt,
    ProcessExt
};
use serde::{Serialize, Deserialize};

use crate::errors::*;


#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
pub struct Client {
    pub pid: u32,
    pub exe: Option<PathBuf>,
}


pub fn get_client(pid: u32, parent: bool) -> Result<Client, ClientInfoError> {
    let sys_pid = Pid::from_u32(pid);
    let mut sys = System::new();   
    sys.refresh_process(sys_pid);
    let mut proc = sys.process(sys_pid)
        .ok_or(ClientInfoError::ProcessNotFound)?;

    if parent {
        let parent_pid_sys = proc.parent()
            .ok_or(ClientInfoError::ParentPidNotFound)?;
        sys.refresh_process(parent_pid_sys);
        proc = sys.process(parent_pid_sys)
            .ok_or(ClientInfoError::ParentProcessNotFound)?;
    }

    let exe = match proc.exe() {
        p if p == Path::new("") => None,
        p => Some(PathBuf::from(p)),
    };

    Ok(Client { pid: proc.pid().as_u32(), exe })
}
