//! Claim extractors for finding implicit decisions in source code.
// Skeleton phase: allow unused until extractors are implemented
#![allow(dead_code)]
//!
//! Each extractor looks for specific patterns that represent implicit claims:
//! - `tls_verify`: TLS certificate verification settings
//! - `jwt_config`: JWT validation configuration
//! - `hardcoded_secrets`: Credentials in source code
//! - `timeout_config`: HTTP/DB/Redis timeout values
//! - `dep_versions`: Vulnerable dependency versions
//! - `cors_config`: CORS allow-origin settings
//! - `rate_limit`: Rate limiting configuration

use crate::types::{ExtractedClaim, Language};

/// Trait for claim extractors.
///
/// Extractors scan file content and return claims about implicit decisions.
pub trait Extractor: Send + Sync {
    /// Unique identifier for this extractor.
    fn name(&self) -> &str;

    /// File types this extractor operates on.
    fn languages(&self) -> &[Language];

    /// Extract claims from a file's content.
    ///
    /// # Arguments
    ///
    /// * `path_segments` - ConceptPath segments derived from the file's location
    /// * `content` - The file content as a string
    /// * `language` - The detected language of the file
    ///
    /// # Returns
    ///
    /// Zero or more extracted claims.
    fn extract(
        &self,
        path_segments: &[String],
        content: &str,
        language: Language,
    ) -> Vec<ExtractedClaim>;
}

/// Registry of available extractors.
pub struct ExtractorRegistry {
    extractors: Vec<Box<dyn Extractor>>,
}

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

impl ExtractorRegistry {
    /// Create a new registry with all built-in extractors.
    pub fn new() -> Self {
        // TODO: Register built-in extractors
        Self { extractors: Vec::new() }
    }

    /// Get extractors applicable to a given language.
    pub fn for_language(&self, language: Language) -> Vec<&dyn Extractor> {
        self.extractors
            .iter()
            .filter(|e| e.languages().contains(&language))
            .map(|e| e.as_ref())
            .collect()
    }

    /// Extract claims from content using all applicable extractors.
    pub fn extract_all(
        &self,
        path_segments: &[String],
        content: &str,
        language: Language,
    ) -> Vec<ExtractedClaim> {
        self.for_language(language)
            .iter()
            .flat_map(|e| e.extract(path_segments, content, language))
            .collect()
    }
}

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

    #[test]
    fn test_registry_creation() {
        let registry = ExtractorRegistry::new();
        // Currently empty, will be populated when extractors are implemented
        assert!(registry.for_language(Language::Rust).is_empty());
    }

    #[test]
    fn test_extract_all_empty() {
        let registry = ExtractorRegistry::new();
        let claims = registry.extract_all(&["rust".to_string()], "fn main() {}", Language::Rust);
        assert!(claims.is_empty());
    }
}
