//! Authentication module for shared API server.
//!
//! This module provides:
//! - API key validation and verification
//! - JWT (JSON Web Token) authentication
//! - Bearer token authentication
//! - Key management (loading/storage)
//! - Authentication error handling
//! - Configurable API key headers
//!
//! API keys are validated against a configured list stored in memory.
//! JWTs are validated using a secret key with HS256 algorithm.

pub mod jwt;

use std::collections::HashSet;
use std::sync::{Arc, RwLock};
use thiserror::Error;
use uuid::Uuid;

/// Authentication errors
#[allow(dead_code)]
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum AuthError {
    /// Missing authorization header in request
    #[error("Missing authorization header")]
    MissingHeader,

    /// Invalid authorization header format
    #[error("Invalid authorization format")]
    InvalidFormat,

    /// Invalid or unknown API key
    #[error("Invalid API key")]
    InvalidKey,

    /// API key has expired
    #[error("Expired API key")]
    ExpiredKey,
}

/// API Key for authentication
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ApiKey(String);

impl ApiKey {
    /// Create a new API key from a string
    pub fn new(key: impl Into<String>) -> Self {
        Self(key.into())
    }

    /// Get the key as a string
    pub fn as_str(&self) -> &str {
        &self.0
    }

    /// Validate API key format (should not be empty and reasonable length)
    pub fn is_valid_format(&self) -> bool {
        let len = self.0.len();
        (8..=256).contains(&len)
            && self
                .0
                .chars()
                .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
    }
}

/// Authentication provider for API key validation
#[derive(Clone, Debug)]
pub struct AuthProvider {
    /// Set of valid API keys
    valid_keys: Arc<RwLock<HashSet<String>>>,

    /// Authentication header name (default: "Authorization")
    #[allow(dead_code)]
    header_name: String,

    /// Authentication prefix (default: "Bearer")
    #[allow(dead_code)]
    auth_prefix: String,

    /// Enable strict key validation
    strict_validation: bool,
}

impl AuthProvider {
    /// Create a new authentication provider with default settings
    pub fn new() -> Self {
        Self {
            valid_keys: Arc::new(RwLock::new(HashSet::new())),
            header_name: "Authorization".to_string(),
            auth_prefix: "Bearer".to_string(),
            strict_validation: true,
        }
    }

    /// Create a new auth provider with custom header and prefix
    pub fn with_config(
        header_name: impl Into<String>,
        auth_prefix: impl Into<String>,
        strict_validation: bool,
    ) -> Self {
        Self {
            valid_keys: Arc::new(RwLock::new(HashSet::new())),
            header_name: header_name.into(),
            auth_prefix: auth_prefix.into(),
            strict_validation,
        }
    }

    /// Add a valid API key
    pub fn add_key(&self, key: ApiKey) -> Result<(), String> {
        if self.strict_validation && !key.is_valid_format() {
            return Err(format!("Invalid API key format: {}", key.as_str()));
        }

        let mut keys = self.valid_keys.write().unwrap();
        keys.insert(key.0);
        Ok(())
    }

    /// Remove an API key
    #[allow(dead_code)]
    pub fn remove_key(&self, key: &ApiKey) -> bool {
        let mut keys = self.valid_keys.write().unwrap();
        keys.remove(key.as_str())
    }

    /// Check if an API key is valid
    #[allow(dead_code)]
    pub fn validate_key(&self, key: &ApiKey) -> Result<(), AuthError> {
        let keys = self.valid_keys.read().unwrap();

        if keys.contains(key.as_str()) {
            Ok(())
        } else {
            Err(AuthError::InvalidKey)
        }
    }

    /// Validate an authorization header
    ///
    /// Expected format: "{prefix} {key}"
    /// Example: "Bearer sk_live_abc123def456..."
    #[allow(dead_code)]
    pub fn validate_header(&self, header_value: &str) -> Result<ApiKey, AuthError> {
        let parts: Vec<&str> = header_value.split_whitespace().collect();

        if parts.len() != 2 {
            return Err(AuthError::InvalidFormat);
        }

        let prefix = parts[0];
        let key_str = parts[1];

        if prefix != self.auth_prefix {
            return Err(AuthError::InvalidFormat);
        }

        let key = ApiKey::new(key_str);

        // Validate the key
        self.validate_key(&key)?;

        Ok(key)
    }

    /// Get the configured header name
    #[allow(dead_code)]
    pub fn header_name(&self) -> &str {
        &self.header_name
    }

    /// Get the configured auth prefix
    #[allow(dead_code)]
    pub fn auth_prefix(&self) -> &str {
        &self.auth_prefix
    }

    /// Get the number of registered keys (for testing/monitoring)
    pub fn key_count(&self) -> usize {
        let keys = self.valid_keys.read().unwrap();
        keys.len()
    }

    /// Clear all keys (useful for testing)
    #[cfg(test)]
    pub fn clear_keys(&self) {
        let mut keys = self.valid_keys.write().unwrap();
        keys.clear();
    }
}

impl Default for AuthProvider {
    fn default() -> Self {
        Self::new()
    }
}

/// Key generator for creating secure API keys
/// Uses UUID v4 for cryptographic randomness
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct KeyGenerator {
    /// Prefix for generated keys (e.g., "sk_live", "sk_test")
    prefix: String,
}

impl KeyGenerator {
    /// Create a new key generator with production prefix
    #[allow(dead_code)]
    pub fn new() -> Self {
        Self {
            prefix: "sk_live".to_string(),
        }
    }

    /// Create a key generator with custom prefix
    #[allow(dead_code)]
    pub fn with_prefix(prefix: impl Into<String>) -> Self {
        Self {
            prefix: prefix.into(),
        }
    }

    /// Generate a new secure API key
    ///
    /// # Format
    ///
    /// Returns a key in format: `{prefix}_{uuid_without_hyphens}`
    /// Example: `sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6`
    ///
    /// # Returns
    ///
    /// An ApiKey ready to be added to an AuthProvider
    ///
    /// # Example
    ///
    /// ```ignore
    /// let gen = KeyGenerator::new();
    /// let key = gen.generate();
    /// println!("New API Key: {}", key.as_str());
    /// // Output: New API Key: sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
    /// ```
    #[allow(dead_code)]
    pub fn generate(&self) -> ApiKey {
        let uuid = Uuid::new_v4();
        let uuid_str = uuid.simple().to_string();
        let key_str = format!("{}_{}", self.prefix, uuid_str);
        ApiKey::new(key_str)
    }

    /// Generate multiple API keys
    #[allow(dead_code)]
    pub fn generate_batch(&self, count: usize) -> Vec<ApiKey> {
        (0..count).map(|_| self.generate()).collect()
    }

    /// Get the current prefix
    #[allow(dead_code)]
    pub fn prefix(&self) -> &str {
        &self.prefix
    }
}

impl Default for KeyGenerator {
    fn default() -> Self {
        Self::new()
    }
}

// Re-export JWT types for convenience
pub use jwt::{Claims, JwtError, JwtProvider};

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

    #[test]
    fn test_api_key_creation() {
        let key = ApiKey::new("sk_live_abc123def456");
        assert_eq!(key.as_str(), "sk_live_abc123def456");
    }

    #[test]
    fn test_api_key_valid_format() {
        let valid_key = ApiKey::new("sk_live_abc123def456");
        assert!(valid_key.is_valid_format());

        let short_key = ApiKey::new("short");
        assert!(!short_key.is_valid_format());

        let too_long = ApiKey::new("a".repeat(300).as_str());
        assert!(!too_long.is_valid_format());

        let invalid_chars = ApiKey::new("sk@live#invalid");
        assert!(!invalid_chars.is_valid_format());
    }

    #[test]
    fn test_auth_provider_creation() {
        let provider = AuthProvider::new();
        assert_eq!(provider.header_name(), "Authorization");
        assert_eq!(provider.auth_prefix(), "Bearer");
        assert_eq!(provider.key_count(), 0);
    }

    #[test]
    fn test_add_valid_key() {
        let provider = AuthProvider::new();
        let key = ApiKey::new("sk_live_abc123def456");

        assert!(provider.add_key(key).is_ok());
        assert_eq!(provider.key_count(), 1);
    }

    #[test]
    fn test_add_invalid_key_format() {
        let provider = AuthProvider::new();
        let invalid_key = ApiKey::new("short");

        let _result = provider.add_key(invalid_key);
        assert!(_result.is_err());
        assert_eq!(provider.key_count(), 0);
    }

    #[test]
    fn test_validate_key() {
        let provider = AuthProvider::new();
        let key = ApiKey::new("sk_live_abc123def456");

        // Should fail before adding
        assert!(provider.validate_key(&key).is_err());

        // Add the key
        provider.add_key(key.clone()).unwrap();

        // Should succeed after adding
        assert!(provider.validate_key(&key).is_ok());
    }

    #[test]
    fn test_validate_header_success() {
        let provider = AuthProvider::new();
        let key = ApiKey::new("sk_live_abc123def456");
        provider.add_key(key.clone()).unwrap();

        let header = "Bearer sk_live_abc123def456";
        let result = provider.validate_header(header);

        assert!(result.is_ok());
        assert_eq!(result.unwrap(), key);
    }

    #[test]
    fn test_validate_header_missing() {
        let provider = AuthProvider::new();
        let _key = ApiKey::new("sk_live_abc123def456");

        let header = "Bearer sk_live_unknown";
        let result = provider.validate_header(header);

        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), AuthError::InvalidKey);
    }

    #[test]
    fn test_validate_header_invalid_format() {
        let provider = AuthProvider::new();

        let header = "InvalidFormat";
        let result = provider.validate_header(header);

        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), AuthError::InvalidFormat);
    }

    #[test]
    fn test_validate_header_wrong_prefix() {
        let provider = AuthProvider::new();
        let key = ApiKey::new("sk_live_abc123def456");
        provider.add_key(key).unwrap();

        let header = "Basic sk_live_abc123def456";
        let result = provider.validate_header(header);

        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), AuthError::InvalidFormat);
    }

    #[test]
    fn test_custom_header_and_prefix() {
        let provider = AuthProvider::with_config("X-API-Key", "Key", true);
        assert_eq!(provider.header_name(), "X-API-Key");
        assert_eq!(provider.auth_prefix(), "Key");

        let key = ApiKey::new("sk_live_abc123def456");
        provider.add_key(key.clone()).unwrap();

        let header = "Key sk_live_abc123def456";
        let result = provider.validate_header(header);
        assert!(result.is_ok());
    }

    #[test]
    fn test_remove_key() {
        let provider = AuthProvider::new();
        let key = ApiKey::new("sk_live_abc123def456");

        provider.add_key(key.clone()).unwrap();
        assert_eq!(provider.key_count(), 1);

        assert!(provider.remove_key(&key));
        assert_eq!(provider.key_count(), 0);

        assert!(!provider.remove_key(&key)); // Already removed
    }

    #[test]
    fn test_multiple_keys() {
        let provider = AuthProvider::new();

        let key1 = ApiKey::new("sk_live_abc123def456");
        let key2 = ApiKey::new("sk_live_xyz789uvw000");
        let key3 = ApiKey::new("sk_live_111222333444");

        provider.add_key(key1.clone()).unwrap();
        provider.add_key(key2.clone()).unwrap();
        provider.add_key(key3.clone()).unwrap();

        assert_eq!(provider.key_count(), 3);

        // All should validate
        assert!(provider.validate_key(&key1).is_ok());
        assert!(provider.validate_key(&key2).is_ok());
        assert!(provider.validate_key(&key3).is_ok());

        // Remove one
        provider.remove_key(&key2);
        assert_eq!(provider.key_count(), 2);

        // Key2 should now fail
        assert!(provider.validate_key(&key2).is_err());

        // Others should still work
        assert!(provider.validate_key(&key1).is_ok());
        assert!(provider.validate_key(&key3).is_ok());
    }

    #[test]
    fn test_non_strict_validation() {
        let provider = AuthProvider::with_config("Authorization", "Bearer", false);

        let invalid_key = ApiKey::new("short@invalid#");
        // Should succeed with non-strict validation
        let _result = provider.add_key(invalid_key.clone());
        // In non-strict mode, we don't validate format on add
        // But we still validate on header validation
    }

    #[test]
    fn test_auth_error_display() {
        assert_eq!(
            AuthError::MissingHeader.to_string(),
            "Missing authorization header"
        );
        assert_eq!(
            AuthError::InvalidFormat.to_string(),
            "Invalid authorization format"
        );
        assert_eq!(AuthError::InvalidKey.to_string(), "Invalid API key");
        assert_eq!(AuthError::ExpiredKey.to_string(), "Expired API key");
    }

    #[test]
    fn test_clear_keys() {
        let provider = AuthProvider::new();
        let key1 = ApiKey::new("sk_live_abc123def456");
        let key2 = ApiKey::new("sk_live_xyz789uvw000");

        provider.add_key(key1).unwrap();
        provider.add_key(key2).unwrap();
        assert_eq!(provider.key_count(), 2);

        provider.clear_keys();
        assert_eq!(provider.key_count(), 0);
    }

    // ============================================================================
    // KeyGenerator Tests
    // ============================================================================

    #[test]
    fn test_key_generator_creation() {
        let gen = KeyGenerator::new();
        assert_eq!(gen.prefix(), "sk_live");
    }

    #[test]
    fn test_key_generator_custom_prefix() {
        let gen = KeyGenerator::with_prefix("sk_test");
        assert_eq!(gen.prefix(), "sk_test");
    }

    #[test]
    fn test_key_generator_default() {
        let gen = KeyGenerator::default();
        assert_eq!(gen.prefix(), "sk_live");
    }

    #[test]
    fn test_generate_key_format() {
        let gen = KeyGenerator::new();
        let key = gen.generate();

        // Should start with prefix
        assert!(key.as_str().starts_with("sk_live_"));

        // Should be exactly 40 characters (7 for "sk_live" + 1 for "_" + 32 for UUID)
        assert_eq!(key.as_str().len(), 40);

        // Should be valid format
        assert!(key.is_valid_format());
    }

    #[test]
    fn test_generate_key_uniqueness() {
        let gen = KeyGenerator::new();

        // Generate 100 keys and verify they're all unique
        let keys: Vec<String> = (0..100).map(|_| gen.generate().0).collect();

        let unique_count = keys.iter().collect::<std::collections::HashSet<_>>().len();
        assert_eq!(unique_count, 100, "All generated keys should be unique");
    }

    #[test]
    fn test_generate_batch() {
        let gen = KeyGenerator::new();
        let keys = gen.generate_batch(5);

        assert_eq!(keys.len(), 5);

        for key in &keys {
            assert!(key.as_str().starts_with("sk_live_"));
            assert!(key.is_valid_format());
        }
    }

    #[test]
    fn test_generate_batch_uniqueness() {
        let gen = KeyGenerator::new();
        let keys = gen.generate_batch(50);

        let unique_count = keys.iter().collect::<std::collections::HashSet<_>>().len();
        assert_eq!(
            unique_count, 50,
            "All batch-generated keys should be unique"
        );
    }

    #[test]
    fn test_generated_key_with_auth_provider() {
        let gen = KeyGenerator::new();
        let provider = AuthProvider::new();

        // Generate and add a key
        let key = gen.generate();
        assert!(provider.add_key(key.clone()).is_ok());

        // Verify it validates
        assert!(provider.validate_key(&key).is_ok());

        // Verify it works with header validation
        let header = format!("Bearer {}", key.as_str());
        let result = provider.validate_header(&header);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), key);
    }

    #[test]
    fn test_key_generator_custom_prefix_format() {
        let gen = KeyGenerator::with_prefix("api_sk");
        let key = gen.generate();

        assert!(key.as_str().starts_with("api_sk_"));
        assert_eq!(key.as_str().len(), 39); // 6 for "api_sk" + 1 for "_" + 32 for UUID
    }

    #[test]
    fn test_multiple_generators_independent() {
        let gen1 = KeyGenerator::with_prefix("sk_live");
        let gen2 = KeyGenerator::with_prefix("sk_test");

        let key1 = gen1.generate();
        let key2 = gen2.generate();

        // Keys should have different prefixes
        assert!(key1.as_str().starts_with("sk_live_"));
        assert!(key2.as_str().starts_with("sk_test_"));

        // Keys should be different
        assert_ne!(key1, key2);
    }

    #[test]
    fn test_generated_key_entropy() {
        let gen = KeyGenerator::new();

        // Generate 10 keys and ensure UUIDs differ significantly
        let keys: Vec<ApiKey> = (0..10).map(|_| gen.generate()).collect();

        // All should be unique (high probability with UUID v4)
        let unique_count = keys.iter().collect::<std::collections::HashSet<_>>().len();
        assert_eq!(unique_count, 10);

        // Each should have different UUID parts
        for i in 0..keys.len() {
            for j in (i + 1)..keys.len() {
                let uuid1 = &keys[i].as_str()[8..]; // Skip "sk_live_"
                let uuid2 = &keys[j].as_str()[8..];
                assert_ne!(uuid1, uuid2);
            }
        }
    }

    #[test]
    fn test_empty_batch_generation() {
        let gen = KeyGenerator::new();
        let keys = gen.generate_batch(0);
        assert_eq!(keys.len(), 0);
    }

    #[test]
    fn test_large_batch_generation() {
        let gen = KeyGenerator::new();
        let keys = gen.generate_batch(1000);

        assert_eq!(keys.len(), 1000);

        // Verify uniqueness (important for security)
        let unique_count = keys.iter().collect::<std::collections::HashSet<_>>().len();
        assert_eq!(unique_count, 1000);

        // Verify all are valid format
        for key in keys {
            assert!(key.is_valid_format());
        }
    }
}
