//! Store and retrieve data using the sopass command.

use crate::error::CAError;
use crate::store::KeyStore;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};

const NOT_IN_STORE: &str = "is not in the password store";

/// Load a [`KeyStore`] with the sopass command.
pub fn pass_load_store(key: &str) -> Result<KeyStore, CAError> {
    let output = Command::new("sopass")
        .arg("value")
        .arg("show")
        .arg(key)
        .stdin(Stdio::null())
        .output()
        .map_err(CAError::PassLoadInvoke)?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
        if stderr.contains(NOT_IN_STORE) {
            return Ok(KeyStore::default());
        } else {
            return Err(CAError::PassLoadFailed(stderr));
        }
    }

    let stdout =
        String::from_utf8(output.stdout).map_err(|e| CAError::Utf8(PathBuf::from("sopass"), e))?;
    KeyStore::from_yaml(&stdout).map_err(CAError::YamlError)
}

/// Save a [`KeyStore`] with the pass command.
pub fn pass_save_store(key: &str, store: &KeyStore) -> Result<(), CAError> {
    let yaml = store.to_yaml();

    let mut child = Command::new("sopass")
        .arg("value")
        .arg("add")
        .arg("--stdin")
        .arg(key)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .map_err(CAError::PassSaveInvoke)?;

    {
        let mut stdin = child.stdin.take().unwrap();
        stdin
            .write_all(yaml.as_bytes())
            .map_err(CAError::PassSavePipe)?;
    }

    let output = child.wait_with_output().map_err(CAError::PassSaveWait)?;
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
        return Err(CAError::PassSaveFailed(stderr));
    }

    Ok(())
}
