pub mod auto_refresh;
pub mod current;
pub mod login;
pub mod output;
pub mod refresh;
pub mod remove;
pub mod save;
pub mod sync;
pub mod use_secret;

use anyhow::Result;
use std::path::Path;

pub fn identity_from_auth_file(path: &Path) -> Result<Option<String>> {
    crate::runtime::auth::identity_from_auth_file(path).map_err(anyhow::Error::from)
}

pub fn email_from_auth_file(path: &Path) -> Result<Option<String>> {
    crate::runtime::auth::email_from_auth_file(path).map_err(anyhow::Error::from)
}

pub fn account_id_from_auth_file(path: &Path) -> Result<Option<String>> {
    crate::runtime::auth::account_id_from_auth_file(path).map_err(anyhow::Error::from)
}

pub fn last_refresh_from_auth_file(path: &Path) -> Result<Option<String>> {
    crate::runtime::auth::last_refresh_from_auth_file(path).map_err(anyhow::Error::from)
}

pub fn identity_key_from_auth_file(path: &Path) -> Result<Option<String>> {
    crate::runtime::auth::identity_key_from_auth_file(path).map_err(anyhow::Error::from)
}

pub fn is_invalid_secret_target(target: &str) -> bool {
    target.contains('/') || target.contains('\\') || target.contains("..")
}

pub fn normalize_secret_file_name(target: &str) -> String {
    if target.ends_with(".json") {
        return target.to_string();
    }
    format!("{target}.json")
}

#[cfg(test)]
mod tests {
    use super::{is_invalid_secret_target, normalize_secret_file_name};

    #[test]
    fn secret_target_validation_rejects_paths_and_traversal() {
        assert!(is_invalid_secret_target("../a.json"));
        assert!(is_invalid_secret_target("a/b.json"));
        assert!(is_invalid_secret_target(r"a\b.json"));
        assert!(!is_invalid_secret_target("alpha"));
        assert!(!is_invalid_secret_target("alpha.json"));
    }

    #[test]
    fn normalize_secret_file_name_appends_json_suffix_only_once() {
        assert_eq!(normalize_secret_file_name("alpha"), "alpha.json");
        assert_eq!(normalize_secret_file_name("alpha.json"), "alpha.json");
    }
}
