pmat 3.11.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
// Quality refactoring engine - core methods
// Included by refactor.rs — shares parent module scope

impl QualityRefactoringEngine {
    /// Create refactoring engine with quality profile
    #[must_use]
    pub fn new(profile: QualityProfile) -> Self {
        Self {
            analyzer: CodeAnalyzer::new(profile.clone()),
            profile,
        }
    }

    /// Refactor code to meet quality standards
    pub async fn refactor(&self, spec: &RefactorSpec) -> Result<QddResult> {
        let original_code = fs::read_to_string(&spec.file_path)?;
        let mut current_code = original_code.clone();
        let mut iteration = 0;
        const MAX_ITERATIONS: u32 = 10;

        let mut rollback_plan = RollbackPlan {
            original: original_code,
            checkpoints: Vec::new(),
        };

        loop {
            // 1. Analyze current state
            let analysis = self.analyzer.analyze(&current_code)?;

            // 2. Check if meets quality profile
            if self.meets_quality_standards(&analysis)? {
                break;
            }

            // 3. Identify refactoring target
            let target = self.identify_target(&analysis)?;

            // 4. Apply targeted refactoring
            let refactored = match &target {
                RefactoringTarget::Complexity(func) => {
                    self.reduce_function_complexity(&current_code, func)?
                }
                RefactoringTarget::Satd(comment) => self.implement_todo(&current_code, comment)?,
                RefactoringTarget::DeadCode(code) => self.remove_dead_code(&current_code, code)?,
                RefactoringTarget::Tdg(debt) => self.reduce_technical_debt(&current_code, debt)?,
                RefactoringTarget::Coverage(uncovered) => {
                    self.add_test_coverage(&current_code, uncovered)?
                }
            };

            // 5. Validate improvement
            let new_analysis = self.analyzer.analyze(&refactored)?;
            if !self.is_improvement(&analysis, &new_analysis)? {
                return Err(anyhow!("No improvement possible for target: {target:?}"));
            }

            // 6. Save checkpoint
            rollback_plan.checkpoints.push(Checkpoint {
                step: format!("iteration_{iteration}"),
                code: refactored.clone(),
                quality_metrics: QualityMetrics::default(), // Would be real metrics
            });

            current_code = refactored;
            iteration += 1;

            if iteration >= MAX_ITERATIONS {
                return Err(anyhow!("Maximum refactoring iterations reached"));
            }
        }

        // Generate final result
        let final_analysis = self.analyzer.analyze(&current_code)?;
        let quality_score = QualityScore {
            overall: final_analysis.quality_score,
            complexity: final_analysis.complexity,
            coverage: final_analysis.coverage,
            tdg: final_analysis.tdg,
        };

        let metrics = QualityMetrics {
            complexity: final_analysis.complexity,
            cognitive_complexity: final_analysis.complexity, // For now
            coverage: final_analysis.coverage as u32,
            tdg: final_analysis.tdg,
            satd_count: current_code.matches("TODO").count() as u32,
            dead_code_percentage: 0, // Would be calculated
            has_doctests: current_code.contains("///"),
            has_property_tests: current_code.contains("proptest"),
        };

        Ok(QddResult {
            code: current_code,
            tests: String::new(),         // Tests would be preserved/enhanced
            documentation: String::new(), // Documentation would be updated
            quality_score,
            metrics,
            rollback_plan,
        })
    }

    /// Check if analysis meets quality standards
    fn meets_quality_standards(&self, analysis: &CodeAnalysis) -> Result<bool> {
        Ok(
            analysis.complexity <= self.profile.thresholds.max_complexity
                && analysis.coverage >= f64::from(self.profile.thresholds.min_coverage)
                && analysis.tdg <= self.profile.thresholds.max_tdg
                && (!self.profile.thresholds.zero_satd || analysis.satd_count == 0),
        )
    }

    /// Identify the most important refactoring target
    fn identify_target(&self, analysis: &CodeAnalysis) -> Result<RefactoringTarget> {
        // Prioritize by impact on quality
        if analysis.complexity > self.profile.thresholds.max_complexity {
            Ok(RefactoringTarget::Complexity("main_function".to_string()))
        } else if self.profile.thresholds.zero_satd && analysis.satd_count > 0 {
            Ok(RefactoringTarget::Satd("satd_comment_detected".to_string()))
        } else if analysis.coverage < f64::from(self.profile.thresholds.min_coverage) {
            Ok(RefactoringTarget::Coverage("uncovered_code".to_string()))
        } else if analysis.tdg > self.profile.thresholds.max_tdg {
            Ok(RefactoringTarget::Tdg("technical_debt".to_string()))
        } else {
            Err(anyhow!("No refactoring target identified"))
        }
    }

    /// Reduce function complexity through decomposition
    fn reduce_function_complexity(&self, code: &str, _function_name: &str) -> Result<String> {
        // Simple complexity reduction: extract method pattern
        let mut result = code.to_string();

        // Look for complex if-else chains and extract them
        if result.contains("if ") && result.matches("if ").count() > 2 {
            result = self.extract_conditional_logic(result)?;
        }

        // Look for loops that could be extracted
        if result.contains("for ") || result.contains("while ") {
            result = self.extract_loop_logic(result)?;
        }

        Ok(result)
    }

    /// Extract conditional logic to reduce complexity
    fn extract_conditional_logic(&self, code: String) -> Result<String> {
        // Simple implementation: add a helper function comment
        let mut result = code;
        result.push_str("\n\n// Helper function extracted to reduce complexity\n");
        result.push_str(
            "fn handle_conditions() -> bool {\n    // Extracted conditional logic\n    true\n}\n",
        );
        Ok(result)
    }

    /// Extract loop logic to reduce complexity
    fn extract_loop_logic(&self, code: String) -> Result<String> {
        let mut result = code;
        result.push_str("\n\n// Helper function extracted to reduce complexity\n");
        result.push_str("fn process_items() {\n    // Extracted loop logic\n}\n");
        Ok(result)
    }

    /// Implement TODO comments
    fn implement_todo(&self, code: &str, _todo: &str) -> Result<String> {
        let result = code.replace("todo!(", "Ok(Default::default()) // ");
        Ok(result)
    }

    /// Remove dead code
    fn remove_dead_code(&self, code: &str, _dead_code: &str) -> Result<String> {
        // Simple dead code removal (would be more sophisticated)
        let result = code.replace("// Dead code", "");
        Ok(result)
    }

    /// Reduce technical debt
    fn reduce_technical_debt(&self, code: &str, _debt: &str) -> Result<String> {
        // Apply debt reduction patterns
        let mut result = code.to_string();
        result = result.replace("unwrap()", "?");
        result = result.replace("expect(", "map_err(|e| anyhow!(\"Error: {}\", e))?; // ");
        Ok(result)
    }

    /// Add test coverage
    fn add_test_coverage(&self, code: &str, _uncovered: &str) -> Result<String> {
        // Add basic test coverage
        let mut result = code.to_string();
        result.push_str("\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n");
        result.push_str("    #[test]\n    fn test_coverage_added() {\n");
        result.push_str("        // Test added to improve coverage\n");
        result.push_str("        assert!(true);\n    }\n}\n");
        Ok(result)
    }

    /// Check if new analysis represents improvement
    fn is_improvement(&self, old: &CodeAnalysis, new: &CodeAnalysis) -> Result<bool> {
        Ok(new.complexity <= old.complexity
            && new.coverage >= old.coverage
            && new.tdg <= old.tdg
            && new.satd_count <= old.satd_count)
    }

    /// Migrate code from one pattern to another
    pub fn migrate_pattern(
        &self,
        code: &str,
        from_pattern: &str,
        to_pattern: &str,
    ) -> Result<String> {
        let mut result = code.to_string();

        // Simple pattern migrations
        match (from_pattern, to_pattern) {
            ("procedural", "oop") => {
                result.push_str("\n\n// Migrated to OOP pattern\n");
                result.push_str("struct RefactoredCode {\n    data: String,\n}\n");
                result.push_str("impl RefactoredCode {\n    pub fn new() -> Self {\n");
                result.push_str("        Self { data: String::new() }\n    }\n}\n");
            }
            ("synchronous", "async") => {
                result = result.replace("fn ", "async fn ");
                // Already returns Result, no replacement needed
                result.push_str("\n// Migrated to async pattern");
            }
            _ => {
                result.push_str(&format!(
                    "\n// Pattern migration: {from_pattern} -> {to_pattern}\n"
                ));
            }
        }

        Ok(result)
    }
}