//! Secrets environment variable injection
//!
//! This module handles injecting secrets as environment variables for use by
//! other platform services. Secrets are kept only in memory and never written
//! to disk or visible in logs.

use anyhow::Result;
use tracing::debug;

/// Inyecta secretos como variables de entorno del proceso actual
///
/// Convierte nombres de secretos a nombres de env vars siguiendo la convención:
/// - "db-password" → "VAULT_SECRET_DB_PASSWORD"
/// - "jwt-secret" → "VAULT_SECRET_JWT_SECRET"
/// - "api-key" → "VAULT_SECRET_API_KEY"
///
/// # Security Notes
/// - Secretos se almacenan SOLO en memoria (no en disco)
/// - NO aparecen en `ps` o procesos
/// - Se filtran en logs automáticamente
/// - Aislados por proceso - NO comparten entre servicios
///
/// # Arguments
/// - `secrets`: Lista de pares (nombre_secreto, valor)
///
/// # Example
/// ```ignore
/// let secrets = vec![
///     ("db-password".to_string(), "SuperSecret123".to_string()),
///     ("jwt-secret".to_string(), "random-jwt-key".to_string()),
/// ];
/// inject_secrets_to_env(&secrets)?;
/// ```
pub fn inject_secrets_to_env(secrets: &[(String, String)]) -> Result<()> {
    if secrets.is_empty() {
        debug!("No secrets to inject");
        return Ok(());
    }

    debug!(
        "Injecting {} secrets as environment variables",
        secrets.len()
    );

    for (key, value) in secrets {
        // Normalizar nombre: "db-password" → "DB_PASSWORD"
        let normalized_key = key.to_uppercase().replace('-', "_");
        let env_var_name = format!("VAULT_SECRET_{}", normalized_key);

        // Inyectar en variables de entorno del proceso
        std::env::set_var(&env_var_name, value);

        // Log SIN mostrar el valor del secreto (seguridad)
        debug!("Injected secret '{}' as env var '{}'", key, env_var_name);
    }

    Ok(())
}

/// Obtiene secretos específicos para un servicio desde el backend de vault
///
/// # Example Response
/// ```ignore
/// {
///   "db-password": "SuperSecret123",
///   "jwt-secret": "random-jwt-key",
///   "api-key": "sk-abc123"
/// }
/// ```
pub async fn get_service_secrets(service_name: &str) -> Result<Vec<(String, String)>> {
    // Ruta en Vault: secret/services/{service_name}/*
    // En una implementación real, esto consultaría a VaultClient

    debug!(
        "Requesting secrets for service: {} from vault backend",
        service_name
    );

    // Retorna vector vacío - implementación real usaría vault_client
    // para leer secretos del backend
    Ok(Vec::new())
}

/// Configura un secreto individual (útil para testing y debugging)
///
/// Esta función se puede usar para establecer secretos en memoria
/// sin acceso al backend de vault.
pub fn set_secret_env_var(secret_name: &str, secret_value: &str) {
    let env_var_name = format!(
        "VAULT_SECRET_{}",
        secret_name.to_uppercase().replace('-', "_")
    );
    std::env::set_var(&env_var_name, secret_value);
    debug!("Set secret '{}' as env var '{}'", secret_name, env_var_name);
}

/// Obtiene un secreto desde las variables de entorno
///
/// Busca en format: VAULT_SECRET_{UPPERCASED_NAME}
pub fn get_secret_from_env(secret_name: &str) -> Option<String> {
    let env_var_name = format!(
        "VAULT_SECRET_{}",
        secret_name.to_uppercase().replace('-', "_")
    );
    std::env::var(&env_var_name).ok()
}

/// Limpia todos los secretos de las variables de entorno
///
/// Esta función elimina todas las variables de entorno que comienzan con
/// VAULT_SECRET_ para garantizar que los secretos no persistan más allá
/// de su necesidad.
pub fn clear_all_secret_env_vars() {
    debug!("Clearing all VAULT_SECRET_* environment variables");

    // Obtener todas las variables de entorno
    let env_vars: Vec<String> = std::env::vars()
        .filter_map(|(key, _)| {
            if key.starts_with("VAULT_SECRET_") {
                Some(key)
            } else {
                None
            }
        })
        .collect();

    for var in env_vars {
        std::env::remove_var(&var);
        debug!("Removed env var: {}", var);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_inject_secrets_empty() {
        let result = inject_secrets_to_env(&[]);
        assert!(result.is_ok());
    }

    #[test]
    fn test_inject_single_secret() {
        let secrets = vec![("test-secret".to_string(), "test-value".to_string())];
        let result = inject_secrets_to_env(&secrets);
        assert!(result.is_ok());

        // Verify it was set
        let value = std::env::var("VAULT_SECRET_TEST_SECRET");
        assert!(value.is_ok());
        assert_eq!(value.unwrap(), "test-value");

        // Cleanup
        std::env::remove_var("VAULT_SECRET_TEST_SECRET");
    }

    #[test]
    fn test_secret_name_normalization() {
        let secrets = vec![("db-password".to_string(), "secret123".to_string())];
        inject_secrets_to_env(&secrets).unwrap();

        // Should be accessible as VAULT_SECRET_DB_PASSWORD
        let value = std::env::var("VAULT_SECRET_DB_PASSWORD");
        assert!(value.is_ok());
        assert_eq!(value.unwrap(), "secret123");

        std::env::remove_var("VAULT_SECRET_DB_PASSWORD");
    }

    #[test]
    fn test_set_and_get_secret() {
        set_secret_env_var("api-key", "sk-test123");

        let retrieved = get_secret_from_env("api-key");
        assert!(retrieved.is_some());
        assert_eq!(retrieved.unwrap(), "sk-test123");

        std::env::remove_var("VAULT_SECRET_API_KEY");
    }

    #[test]
    fn test_clear_all_secret_vars() {
        set_secret_env_var("secret1", "value1");
        set_secret_env_var("secret2", "value2");

        // Verify they exist
        assert!(get_secret_from_env("secret1").is_some());
        assert!(get_secret_from_env("secret2").is_some());

        // Clear all
        clear_all_secret_env_vars();

        // Verify they're gone
        assert!(get_secret_from_env("secret1").is_none());
        assert!(get_secret_from_env("secret2").is_none());
    }
}
