pmat 3.15.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
// Deep context orchestrator pipeline methods - analyze, discover, build DAG, generate reports

impl FeatureFlags {
    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    /// All.
    pub fn all() -> Self {
        Self {
            ast_analysis: true,
            complexity_analysis: true,
            churn_analysis: true,
            satd_analysis: true,
            provability_analysis: true,
            dead_code_analysis: true,
            dependency_analysis: true,
            hotspot_detection: true,
        }
    }

    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    /// Essential.
    pub fn essential() -> Self {
        Self {
            ast_analysis: true,
            complexity_analysis: true,
            churn_analysis: false,
            satd_analysis: true,
            provability_analysis: false,
            dead_code_analysis: true,
            dependency_analysis: true,
            hotspot_detection: true,
        }
    }
}

impl DeepContextOrchestrator {
    /// Create new orchestrator with configured services
    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    pub fn new(
        ast_engine: Arc<UnifiedAstEngine>,
        intelligence: Arc<CodeIntelligence>,
        cache_manager: Arc<UnifiedCacheManager>,
    ) -> Self {
        Self {
            ast_engine,
            intelligence,
            cache_manager,
            max_concurrency: num_cpus::get() * 2,
        }
    }

    /// Perform comprehensive deep context analysis
    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    pub async fn analyze(&self, config: DeepContextConfig) -> Result<DeepContextReport> {
        let start_time = Instant::now();
        info!("Starting deep context analysis for {:?}", config.project_path);

        // Phase 1: Discover files with pattern matching
        let file_paths = self.discover_files(&config).await?;
        info!("Discovered {} files for analysis", file_paths.len());

        // Phase 2: Build unified DAG with parallel AST parsing
        let dag = self.build_unified_dag(&file_paths, &config).await?;
        info!("Built unified DAG with nodes");

        // Phase 3: Perform comprehensive analysis
        let request = OrchestrationRequest {
            dag: dag.clone(),
            features: config.features,
            performance_hint: config.performance_mode,
        };

        // For now, use a simplified analysis approach
        let analysis_results = self.perform_analysis(&request).await?;

        // Phase 4: Generate report and recommendations
        let report = self.generate_report(
            file_paths.len(),
            start_time.elapsed(),
            analysis_results,
        ).await?;

        info!(
            "Deep context analysis completed: {} files in {:?}",
            report.file_count,
            report.analysis_duration
        );

        Ok(report)
    }

    /// Discover files based on include/exclude patterns
    async fn discover_files(&self, config: &DeepContextConfig) -> Result<Vec<PathBuf>> {
        use walkdir::WalkDir;

        // Default source file extensions
        let source_extensions = [
            "rs", "js", "ts", "jsx", "tsx", "py", "cpp", "c", "h", "hpp",
            "java", "go", "php", "rb", "swift", "lean"
        ];

        // Default exclusion directory names
        let exclude_dirs = [
            "target", "node_modules", ".git", "build", "dist", "__pycache__",
            ".next", "vendor", "deps"
        ];

        // Walk directory and filter files
        let mut file_paths = Vec::new();
        for entry in WalkDir::new(&config.project_path)
            .follow_links(false)
            .into_iter()
            .filter_map(|e| e.ok())
            .filter(|e| e.file_type().is_file())
        {
            let path = entry.path();

            // Check if file should be excluded
            let should_exclude = path.components().any(|comp| {
                if let Some(name) = comp.as_os_str().to_str() {
                    exclude_dirs.contains(&name) || name.starts_with('.')
                } else {
                    false
                }
            });

            if should_exclude {
                continue;
            }

            // Check file extension
            if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
                if source_extensions.contains(&ext) {
                    file_paths.push(path.to_path_buf());
                }
            }
        }

        // Sort for deterministic ordering
        file_paths.sort_by(|a, b| a.as_os_str().cmp(b.as_os_str()));
        info!("Discovered {} source files", file_paths.len());
        Ok(file_paths)
    }

    /// Build unified DAG with parallel AST parsing
    async fn build_unified_dag(
        &self,
        file_paths: &[PathBuf],
        config: &DeepContextConfig,
    ) -> Result<Arc<AstDag>> {
        let semaphore = Arc::new(Semaphore::new(self.max_concurrency));
        let dag = Arc::new(AstDag::new());
        let parse_results = Arc::new(DashMap::new());

        debug!("Starting parallel AST parsing for {} files", file_paths.len());

        // Create parsing tasks with bounded concurrency
        let tasks: Vec<_> = file_paths.iter().enumerate().map(|(index, path)| {
            let sem = semaphore.clone();
            let dag = dag.clone();
            let path = path.clone();
            let ast_engine = self.ast_engine.clone();
            let cache_manager = self.cache_manager.clone();
            let results = parse_results.clone();
            let use_cache = matches!(config.cache_strategy, CacheStrategy::Aggressive | CacheStrategy::Normal);

            tokio::spawn(async move {
                let _permit = sem.acquire().await?;

                // Create a minimal AST node for files we can't fully parse yet
                // This ensures the system remains functional while providing basic structure
                use crate::models::unified_ast::{UnifiedAstNode, AstKind, NodeMetadata, Language};

                let minimal_ast = UnifiedAstNode {
                    key: index as u32,
                    kind: AstKind::Module,
                    metadata: NodeMetadata::Module { name: path.file_name().and_then(|n| n.to_str()).unwrap_or("unknown").to_string() },
                    source_range: std::ops::Range { start: 0, end: 0 },
                    language: Language::Rust, // TRACKED: Detect language from extension
                    children: Vec::new(),
                    parent: None,
                    flags: Default::default(),
                    properties: Default::default(),
                    proof_annotations: Default::default(),
                };

                // Add node to DAG - note: DAG needs to be mutable
                // For now, just track success
                results.insert(index, Ok(()));

                Ok::<(), anyhow::Error>(())
            })
        }).collect();

        // Wait for all parsing tasks to complete
        let _results: Vec<_> = futures::future::join_all(tasks).await;

        // Check for parsing errors
        let mut error_count = 0;
        for (index, result) in parse_results.iter() {
            if result.is_err() {
                error_count += 1;
                debug!("Parse error for file {}: {:?}", index, result);
            }
        }

        if error_count > 0 {
            info!("Parsing completed with {} errors out of {} files", error_count, file_paths.len());
        }

        Ok(dag)
    }

    /// Perform comprehensive analysis using the orchestration request
    async fn perform_analysis(&self, _request: &OrchestrationRequest) -> Result<()> {
        // TRACKED: Integrate with existing CodeIntelligence service
        // For now, just return success
        Ok(())
    }

    /// Generate comprehensive analysis report
    async fn generate_report(
        &self,
        file_count: usize,
        duration: std::time::Duration,
        _analysis_results: (), // TRACKED: Replace with actual analysis results
    ) -> Result<DeepContextReport> {
        // TRACKED: Extract actual metrics from analysis results
        let complexity_summary = ComplexitySummary {
            total_functions: 150, // Placeholder
            high_complexity_functions: 12,
            avg_cyclomatic: 4.2,
            avg_cognitive: 6.8,
            complexity_distribution: vec![
                (1, 45), (2, 38), (3, 25), (4, 18), (5, 12), (6, 8), (7, 4)
            ],
        };

        let hotspots = vec![
            // TRACKED: Generate actual hotspots from analysis
        ];

        let recommendations = vec![
            Recommendation {
                category: RecommendationCategory::Refactoring,
                title: "Reduce complexity in high-complexity functions".to_string(),
                description: "Consider breaking down functions with cyclomatic complexity > 10".to_string(),
                impact: RecommendationImpact::High,
                effort: RecommendationEffort::Medium,
            },
        ];

        Ok(DeepContextReport {
            file_count,
            analysis_duration: duration,
            ast_nodes: file_count * 50, // Placeholder estimate
            dependencies: 0, // TRACKED: Count actual dependencies
            complexity_summary,
            hotspots,
            recommendations,
        })
    }
}