//! API Key Strength Validation
//!
//! Validates that API keys meet security requirements

use serde::{Deserialize, Serialize};

/// Key strength level
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum KeyStrength {
    Weak,
    Medium,
    Strong,
    VeryStrong,
}

impl KeyStrength {
    pub fn as_str(&self) -> &'static str {
        match self {
            KeyStrength::Weak => "weak",
            KeyStrength::Medium => "medium",
            KeyStrength::Strong => "strong",
            KeyStrength::VeryStrong => "very_strong",
        }
    }

    pub fn is_acceptable(&self) -> bool {
        !matches!(self, KeyStrength::Weak)
    }
}

/// Key strength validation result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrengthResult {
    pub strength: KeyStrength,
    pub score: u32,
    pub max_score: u32,
    pub issues: Vec<String>,
    pub suggestions: Vec<String>,
}

/// Key strength validator
pub struct KeyStrengthValidator {
    min_length: usize,
    require_prefix: bool,
}

impl Default for KeyStrengthValidator {
    fn default() -> Self {
        Self {
            min_length: 32,
            require_prefix: true,
        }
    }
}

impl KeyStrengthValidator {
    pub fn new(min_length: usize, require_prefix: bool) -> Self {
        Self {
            min_length,
            require_prefix,
        }
    }

    /// Validate key strength
    pub fn validate(&self, key: &str) -> StrengthResult {
        let mut score: u32 = 0;
        let mut issues = Vec::new();
        let mut suggestions = Vec::new();

        // Check length
        if key.len() >= self.min_length {
            score += 25;
        } else {
            issues.push(format!(
                "Key length {} is less than minimum {}",
                key.len(),
                self.min_length
            ));
            suggestions.push(format!("Use at least {} characters", self.min_length));
        }

        // Check for valid prefix
        let valid_prefixes = ["msys_", "muser_", "msvc_", "mint_", "memg_"];
        let has_valid_prefix = valid_prefixes.iter().any(|p| key.starts_with(p));

        if has_valid_prefix {
            score += 25;
        } else if self.require_prefix {
            issues.push("Key does not have a valid prefix".to_string());
            suggestions.push("Use a valid prefix: msys_, muser_, msvc_, mint_, memg_".to_string());
        }

        // Check entropy (character variety)
        let has_lowercase = key.chars().any(|c| c.is_ascii_lowercase());
        let has_uppercase = key.chars().any(|c| c.is_ascii_uppercase());
        let has_digit = key.chars().any(|c| c.is_ascii_digit());
        let has_special = key.chars().any(|c| !c.is_ascii_alphanumeric());

        let entropy_count = [has_lowercase, has_uppercase, has_digit, has_special]
            .iter()
            .filter(|&&x| x)
            .count();

        score += (entropy_count as u32) * 12;

        if entropy_count < 2 {
            issues.push("Low character variety".to_string());
            suggestions
                .push("Include lowercase, uppercase, digits, and special characters".to_string());
        }

        // Check for sequential characters
        let has_sequential = key
            .as_bytes()
            .windows(3)
            .any(|w| w[1] == w[0] + 1 && w[2] == w[1] + 1);

        if has_sequential {
            score = score.saturating_sub(10);
            issues.push("Contains sequential characters".to_string());
        }

        // Check for repeated characters
        let has_repeated = key
            .as_bytes()
            .windows(3)
            .any(|w| w[0] == w[1] && w[1] == w[2]);

        if has_repeated {
            score = score.saturating_sub(10);
            issues.push("Contains repeated characters".to_string());
        }

        // Determine strength level
        let strength = if score >= 80 {
            KeyStrength::VeryStrong
        } else if score >= 60 {
            KeyStrength::Strong
        } else if score >= 40 {
            KeyStrength::Medium
        } else {
            KeyStrength::Weak
        };

        StrengthResult {
            strength,
            score: score.min(100),
            max_score: 100,
            issues,
            suggestions,
        }
    }

    /// Check if key is acceptable
    pub fn is_acceptable(&self, key: &str) -> bool {
        self.validate(key).strength.is_acceptable()
    }
}

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

    #[test]
    fn test_strong_key() {
        let validator = KeyStrengthValidator::default();
        let result = validator.validate("msvc_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6");

        assert!(result.strength.is_acceptable());
        assert!(result.score >= 60);
    }

    #[test]
    fn test_weak_key() {
        let validator = KeyStrengthValidator::default();
        let result = validator.validate("short");

        assert_eq!(result.strength, KeyStrength::Weak);
        assert!(!result.issues.is_empty());
    }

    #[test]
    fn test_sequential_penalty() {
        let validator = KeyStrengthValidator::default();
        let result_with = validator.validate("msvc_abc123def456ghi789jkl012mno345");
        let result_without = validator.validate("msvc_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5");

        // Sequential characters should reduce score
        assert!(
            result_without.score >= result_with.score
                || result_with.issues.len() <= result_without.issues.len()
        );
    }

    #[test]
    fn test_key_strength_serialization() {
        let result = StrengthResult {
            strength: KeyStrength::Strong,
            score: 75,
            max_score: 100,
            issues: vec![],
            suggestions: vec![],
        };

        let json = serde_json::to_string(&result).unwrap();
        assert!(json.contains("\"strong\""));
    }
}
