//! Utility functions for SSH CA tool.

use crate::error::CAError;
use std::fs::{create_dir_all, File, Permissions};
use std::io::Write;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use time::macros::format_description;
use time::OffsetDateTime;

pub(crate) fn read<P: AsRef<Path>>(filename: P) -> Result<Vec<u8>, CAError> {
    let filename = filename.as_ref();
    std::fs::read(filename).map_err(|err| CAError::ReadError(filename.to_path_buf(), err))
}

pub(crate) fn read_as_string<P: AsRef<Path>>(filename: P) -> Result<String, CAError> {
    let filename = filename.as_ref();
    let bytes = read(filename)?;
    String::from_utf8(bytes).map_err(|err| CAError::Utf8(filename.to_path_buf(), err))
}

/// Write string to file.
pub fn write_string<P: AsRef<Path>>(filename: P, s: &str) -> Result<(), CAError> {
    let filename = filename.as_ref();
    if let Some(parent) = filename.parent() {
        create_dir_all(parent).map_err(|e| CAError::CreateDir(parent.into(), e))?;
    }
    let mut file =
        File::create(filename).map_err(|err| CAError::Create(filename.to_path_buf(), err))?;
    let ro_user = Permissions::from_mode(0o600);
    file.set_permissions(ro_user)
        .map_err(|err| CAError::SetPerm(filename.to_path_buf(), err))?;
    file.write_all(s.as_bytes())
        .map_err(|err| CAError::Write(filename.to_path_buf(), err))?;
    Ok(())
}

pub(crate) fn prompt_token() {
    eprintln!("You may need to touch the security token button now");
}

pub(crate) fn format_timestamp(valid_until: OffsetDateTime) -> Result<String, CAError> {
    let format = format_description!("[year]:[month]:[day]T[hour]:[minute]:[second]");
    let valid_until = valid_until.format(&format).map_err(CAError::TimeFormat)?;
    Ok(valid_until)
}
