use regex::Regex;
use lazy_static::lazy_static;

pub struct RedactionRule {
    pub name: String,
    pub pattern: Regex,
    pub replacement: String,
}

pub struct SecretSentinel {
    rules: Vec<RedactionRule>,
}

lazy_static! {
    static ref OPENAI_KEY: Regex = Regex::new(r"sk-[a-zA-Z0-9]{48}").unwrap();
    static ref AWS_KEY: Regex = Regex::new(r"AKIA[0-9A-Z]{16}").unwrap();
    static ref GENERIC_SECRET: Regex = Regex::new(r"(?i)(password|secret|key|token)\s*[:=]\s*[^\s]+").unwrap();
}

impl SecretSentinel {
    pub fn new_default() -> Self {
        let rules = vec![
            RedactionRule {
                name: "OpenAI API Key".into(),
                pattern: OPENAI_KEY.clone(),
                replacement: "[REDACTED OPENAI KEY]".into(),
            },
            RedactionRule {
                name: "AWS Access Key".into(),
                pattern: AWS_KEY.clone(),
                replacement: "[REDACTED AWS KEY]".into(),
            },
            RedactionRule {
                name: "Generic Secret".into(),
                pattern: GENERIC_SECRET.clone(),
                replacement: "$1: [REDACTED]".into(),
            },
        ];
        Self { rules }
    }

    pub fn scrub_text(&self, input: &str) -> String {
        let mut scrubbed = input.to_string();
        for rule in &self.rules {
            scrubbed = rule.pattern.replace_all(&scrubbed, &rule.replacement).to_string();
        }
        scrubbed
    }

    pub fn contains_secrets(&self, input: &str) -> bool {
        self.rules.iter().any(|rule| rule.pattern.is_match(input))
    }
}

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

    #[test]
    fn test_scrub_openai_key() {
        let sentinel = SecretSentinel::new_default();
        let input = "My key is sk-1234567890abcdef1234567890abcdef1234567890abcdef";
        let output = sentinel.scrub_text(input);
        assert!(output.contains("[REDACTED OPENAI KEY]"));
        assert!(!output.contains("sk-1234567890"));
    }

    #[test]
    fn test_scrub_generic_password() {
        let sentinel = SecretSentinel::new_default();
        let input = "login with password: my-secret-password now";
        let output = sentinel.scrub_text(input);
        assert!(output.contains("password: [REDACTED]"));
    }

    #[test]
    fn test_contains_secrets() {
        let sentinel = SecretSentinel::new_default();
        assert!(sentinel.contains_secrets("AKIAIOSFODNN7EXAMPLE"));
        assert!(!sentinel.contains_secrets("nothing sensitive here"));
    }
}
