//! API key bootstrap utilities (P4.2 Authentication).
//!
//! This module provides utilities for bootstrapping the root API key from
//! environment variables on first startup.

use stemedb_storage::{ApiKeyRecord, ApiKeyRole, ApiKeyStore};
use tracing::{info, warn};

/// Environment variable for the root API key.
pub const ROOT_API_KEY_ENV: &str = "STEMEDB_ROOT_API_KEY";

/// Environment variable to enable API key authentication.
pub const AUTH_ENABLED_ENV: &str = "STEMEDB_AUTH_ENABLED";

/// Environment variable to require auth for all endpoints (not just admin).
pub const AUTH_REQUIRE_ALL_ENV: &str = "STEMEDB_AUTH_REQUIRE_ALL";

/// Hash an API key using BLAKE3.
pub fn hash_api_key(raw_key: &str) -> [u8; 32] {
    *blake3::hash(raw_key.as_bytes()).as_bytes()
}

/// Bootstrap the root API key from environment variable.
///
/// If `STEMEDB_ROOT_API_KEY` is set and the key doesn't already exist,
/// creates an admin key record in the store.
///
/// # Example
///
/// ```ignore
/// // Set in environment before starting:
/// // STEMEDB_ROOT_API_KEY=steme_live_your_secure_key_here
///
/// // In startup code:
/// bootstrap_root_api_key(&api_key_store).await?;
/// ```
pub async fn bootstrap_root_api_key<A: ApiKeyStore>(api_key_store: &A) -> Result<(), String> {
    let raw_key = match std::env::var(ROOT_API_KEY_ENV) {
        Ok(key) => key,
        Err(_) => {
            info!("No {} set, skipping root API key bootstrap", ROOT_API_KEY_ENV);
            return Ok(());
        }
    };

    // Validate key format
    if !raw_key.starts_with("steme_") {
        warn!("{} must start with 'steme_' prefix (e.g., steme_live_yourkey)", ROOT_API_KEY_ENV);
        return Err(format!(
            "{} must start with 'steme_' prefix (e.g., steme_live_yourkey)",
            ROOT_API_KEY_ENV
        ));
    }

    if raw_key.len() < 20 {
        warn!("{} is too short, should be at least 20 characters", ROOT_API_KEY_ENV);
        return Err(format!("{} is too short, should be at least 20 characters", ROOT_API_KEY_ENV));
    }

    let key_hash = hash_api_key(&raw_key);
    let key_prefix: String = raw_key.chars().take(12).collect();

    // Check if key already exists
    match api_key_store.get_key_by_hash(&key_hash).await {
        Ok(Some(_)) => {
            info!(
                key_prefix = %key_prefix,
                "Root API key already exists, skipping bootstrap"
            );
            return Ok(());
        }
        Ok(None) => {
            // Key doesn't exist, proceed with bootstrap
        }
        Err(e) => {
            warn!(error = %e, "Failed to check for existing root key");
            return Err(format!("Failed to check for existing root key: {}", e));
        }
    }

    // Get current timestamp
    let now = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_secs())
        .unwrap_or(0);

    // Create root admin key record
    let record = ApiKeyRecord::new(
        key_hash,
        key_prefix.clone(),
        ApiKeyRole::Admin,
        "root_bootstrap".to_string(),
        now,
    );

    // Store the key
    if let Err(e) = api_key_store.put_key(&key_hash, &record).await {
        warn!(error = %e, "Failed to bootstrap root API key");
        return Err(format!("Failed to bootstrap root API key: {}", e));
    }

    info!(
        key_prefix = %key_prefix,
        "Bootstrapped root API key from environment"
    );

    Ok(())
}

/// Check if API authentication is enabled via environment variable.
pub fn is_auth_enabled() -> bool {
    std::env::var(AUTH_ENABLED_ENV)
        .map(|v| v.eq_ignore_ascii_case("true") || v == "1")
        .unwrap_or(false)
}

/// Check if auth should be required for all endpoints (not just admin).
pub fn is_auth_require_all() -> bool {
    std::env::var(AUTH_REQUIRE_ALL_ENV)
        .map(|v| v.eq_ignore_ascii_case("true") || v == "1")
        .unwrap_or(false)
}

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

    #[test]
    fn test_hash_api_key() {
        let key = "steme_test_abc123";
        let hash = hash_api_key(key);
        assert_eq!(hash.len(), 32);

        // Deterministic
        let hash2 = hash_api_key(key);
        assert_eq!(hash, hash2);
    }

    #[test]
    fn test_is_auth_enabled() {
        // Without env var set
        std::env::remove_var(AUTH_ENABLED_ENV);
        assert!(!is_auth_enabled());

        // With env var set to "true"
        std::env::set_var(AUTH_ENABLED_ENV, "true");
        assert!(is_auth_enabled());

        // With env var set to "1"
        std::env::set_var(AUTH_ENABLED_ENV, "1");
        assert!(is_auth_enabled());

        // With env var set to "false"
        std::env::set_var(AUTH_ENABLED_ENV, "false");
        assert!(!is_auth_enabled());

        // Cleanup
        std::env::remove_var(AUTH_ENABLED_ENV);
    }
}
