//! Unreal Engine Performance extractor.
//!
//! Detects performance pitfalls in Unreal Engine C++ code, such as:
//! - Synchronous asset loading on the game thread (causes hitches)
//! - Expensive operations in loops

use regex::Regex;
use stemedb_core::types::ObjectValue;

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

/// Extractor for Unreal Engine performance patterns.
pub struct UnrealPerformanceExtractor {
    /// Synchronous loading detection
    sync_load: Regex,
}

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

impl UnrealPerformanceExtractor {
    /// Create a new Unreal performance extractor with compiled regexes.
    ///
    /// # Panics
    /// Panics if regex patterns are invalid.
    #[allow(clippy::expect_used)]
    pub fn new() -> Self {
        Self {
            // Matches LoadSynchronous, StaticLoadObject, etc.
            sync_load: Regex::new(
                r"(?i)(LoadSynchronous|StaticLoadObject|StaticLoadClass|LoadObject<[^>]*>)\s*\(",
            )
            .expect("valid regex"),
        }
    }

    fn check_pattern(
        &self,
        content: &str,
        pattern: &Regex,
        path_segments: &[String],
        file: &str,
        leaf: &str,
        desc_template: &str,
    ) -> Vec<ExtractedClaim> {
        let mut claims = Vec::new();

        for (line_idx, line) in content.lines().enumerate() {
            if let Some(matched) = pattern.find(line) {
                let mut concept_path = path_segments.to_vec();
                concept_path.push("unreal".to_string());
                concept_path.push("performance".to_string());
                concept_path.push(leaf.to_string());

                claims.push(ExtractedClaim {
                    concept_path: format!("code://{}", concept_path.join("/")),
                    predicate: "sync_load".to_string(),
                    value: ObjectValue::Boolean(true),
                    file: file.to_string(),
                    line: line_idx + 1,
                    matched_text: matched.as_str().to_string(),
                    confidence: 1.0,
                    description: desc_template.to_string(),
                });
            }
        }

        claims
    }
}

impl Extractor for UnrealPerformanceExtractor {
    fn name(&self) -> &str {
        "unreal_performance"
    }

    fn languages(&self) -> &[Language] {
        &[Language::Cpp]
    }

    fn extract(
        &self,
        path_segments: &[String],
        content: &str,
        language: Language,
        file: &str,
    ) -> Vec<ExtractedClaim> {
        if language != Language::Cpp {
            return vec![];
        }

        let mut claims = Vec::new();

        claims.extend(self.check_pattern(
            content,
            &self.sync_load,
            path_segments,
            file,
            "sync_loading",
            "Synchronous loading blocks the game thread and causes hitches",
        ));

        claims
    }
}

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

    #[test]
    fn test_sync_load_detection() {
        let extractor = UnrealPerformanceExtractor::new();
        let content = r#"
            // Bad: sync load
            UTexture2D* Tex = DefaultProfileImage.LoadSynchronous();
            
            // Also bad: static load
            UObject* Obj = StaticLoadObject(UTexture2D::StaticClass(), nullptr, TEXT("/Game/UI/Logo"));
        "#;

        let claims = extractor.extract(
            &["cpp".to_string()],
            content,
            Language::Cpp,
            "Source/MyGame/MyActor.cpp",
        );

        assert_eq!(claims.len(), 2);
        assert_eq!(claims[0].concept_path, "code://cpp/unreal/performance/sync_loading");
        assert_eq!(claims[1].concept_path, "code://cpp/unreal/performance/sync_loading");
    }
}
