debtmap 0.16.6

Code complexity and technical debt analyzer
Documentation
use crate::refactoring::{
    ComplexityLevel, EffortEstimate, FunctionalPattern, Priority, QualityAssessment,
    Recommendation, RefactoringAnalysis, RefactoringExample, RefactoringOpportunity,
};

#[derive(Default)]
pub struct RefactoringGuidanceGenerator;

impl RefactoringGuidanceGenerator {
    pub fn new() -> Self {
        Self
    }

    /// Classify pattern category for collection transformations
    fn is_collection_pattern(pattern: &FunctionalPattern) -> Option<&'static str> {
        match pattern {
            FunctionalPattern::MapOverLoop => Some("Replace loops with map"),
            FunctionalPattern::FilterPredicate => Some("Extract filter predicates"),
            FunctionalPattern::FoldAccumulation => Some("Use fold for aggregation"),
            _ => None,
        }
    }

    /// Classify pattern category for control flow patterns
    fn is_control_flow_pattern(pattern: &FunctionalPattern) -> Option<&'static str> {
        match pattern {
            FunctionalPattern::PatternMatchOverIfElse => Some("Pattern matching"),
            FunctionalPattern::Recursion => Some("Recursion"),
            _ => None,
        }
    }

    /// Classify pattern category for composition patterns
    fn is_composition_pattern(pattern: &FunctionalPattern) -> Option<&'static str> {
        match pattern {
            FunctionalPattern::ComposeFunctions => Some("Compose functions"),
            FunctionalPattern::PartialApplication => Some("Partial application"),
            FunctionalPattern::Pipeline => Some("Function pipeline"),
            _ => None,
        }
    }

    fn format_complexity_level(level: &ComplexityLevel) -> &'static str {
        match level {
            ComplexityLevel::Low => "LOW",
            ComplexityLevel::Moderate => "MODERATE",
            ComplexityLevel::High => "HIGH",
            ComplexityLevel::Severe => "SEVERE",
        }
    }

    fn format_refactoring_strategy(level: &ComplexityLevel) -> &'static str {
        match level {
            ComplexityLevel::Moderate => "direct functional transformation",
            ComplexityLevel::High => "decompose-then-transform",
            ComplexityLevel::Severe => "architectural refactoring",
            _ => "no",
        }
    }

    fn format_benefits_list(benefits: &[String]) -> String {
        if benefits.is_empty() {
            String::new()
        } else {
            let mut output = String::from("BENEFITS:\n");
            for benefit in benefits {
                output.push_str(&format!("{}\n", benefit));
            }
            output
        }
    }

    fn get_priority_icon(priority: &Priority) -> &'static str {
        match priority {
            Priority::Critical => "[ERROR]",
            Priority::High => "[WARN]",
            Priority::Medium => "[WARN]",
            Priority::Low => "[OK]",
        }
    }

    fn get_effort_string(effort: &EffortEstimate) -> &'static str {
        match effort {
            EffortEstimate::Trivial => "< 15 min",
            EffortEstimate::Low => "15-60 min",
            EffortEstimate::Medium => "1-4 hours",
            EffortEstimate::High => "4-8 hours",
            EffortEstimate::Significant => "> 8 hours",
        }
    }

    pub fn generate_guidance(&self, analysis: &RefactoringAnalysis) -> String {
        let mut output = String::new();

        // Add header based on quality assessment
        if analysis.quality_assessment.overall_score > 0.8 {
            output.push_str(&format!("[OK] Good Example: {}\n", analysis.function_name));
            output.push_str(&self.format_strengths(&analysis.quality_assessment));
        } else {
            output.push_str(&format!(
                "[PERF] Refactoring Opportunity: {}\n",
                analysis.function_name
            ));
            output.push_str(&self.format_opportunities(&analysis.refactoring_opportunities));
        }

        // Add recommendations
        if !analysis.recommendations.is_empty() {
            output.push_str("\n## Recommendations\n\n");
            for rec in &analysis.recommendations {
                output.push_str(&self.format_recommendation(rec));
            }
        }

        output
    }

    fn format_strengths(&self, quality: &QualityAssessment) -> String {
        let mut output = String::new();

        if !quality.strengths.is_empty() {
            output.push_str("Strengths:\n");
            for strength in &quality.strengths {
                output.push_str(&format!("{}\n", strength));
            }
        }

        output
    }

    fn format_opportunities(&self, opportunities: &[RefactoringOpportunity]) -> String {
        let mut output = String::new();

        for opportunity in opportunities {
            match opportunity {
                RefactoringOpportunity::ExtractPureFunctions {
                    complexity_level,
                    suggested_functions,
                    functional_patterns,
                    benefits,
                    ..
                } => {
                    output.push_str(&format!(
                        "\n{} Complexity Detected\n",
                        Self::format_complexity_level(complexity_level)
                    ));

                    output.push_str(&format!(
                        "ACTION: Extract {} pure functions using {} strategy\n",
                        suggested_functions.len(),
                        Self::format_refactoring_strategy(complexity_level)
                    ));

                    if !functional_patterns.is_empty() {
                        output.push_str("PATTERNS: ");
                        let patterns: Vec<String> = functional_patterns
                            .iter()
                            .map(|p| self.pattern_to_string(p))
                            .collect();
                        output.push_str(&patterns.join(", "));
                        output.push('\n');
                    }

                    output.push_str(&Self::format_benefits_list(benefits));
                }
                RefactoringOpportunity::ConvertToFunctionalStyle {
                    target_patterns,
                    benefits,
                    ..
                } => {
                    output.push_str("\nFunctional Transformation Opportunity\n");
                    output.push_str("ACTION: Apply functional patterns: ");
                    let patterns: Vec<String> = target_patterns
                        .iter()
                        .map(|p| self.pattern_to_string(p))
                        .collect();
                    output.push_str(&patterns.join(", "));
                    output.push('\n');

                    output.push_str(&Self::format_benefits_list(benefits));
                }
                RefactoringOpportunity::ExtractSideEffects {
                    pure_core,
                    benefits,
                    ..
                } => {
                    output.push_str("\nSide Effect Extraction Needed\n");
                    output.push_str(&format!(
                        "ACTION: Extract pure function '{}' and move I/O to boundaries\n",
                        pure_core.name
                    ));

                    output.push_str(&Self::format_benefits_list(benefits));
                }
            }
        }

        output
    }

    fn format_recommendation(&self, rec: &Recommendation) -> String {
        let mut output = String::new();

        let priority_icon = Self::get_priority_icon(&rec.priority);
        let effort_str = Self::get_effort_string(&rec.effort_estimate);

        output.push_str(&format!(
            "{} {} [Effort: {}]\n",
            priority_icon, rec.title, effort_str
        ));
        output.push_str(&format!("   {}\n", rec.description));

        if let Some(example) = &rec.example {
            output.push_str(&self.format_example(example));
        }

        output.push('\n');
        output
    }

    fn format_example(&self, example: &RefactoringExample) -> String {
        let mut output = String::new();

        output.push_str("\n   Example:\n");
        output.push_str("   Before:\n");
        for line in example.before.lines() {
            output.push_str(&format!("     {}\n", line));
        }
        output.push_str("   After:\n");
        for line in example.after.lines() {
            output.push_str(&format!("     {}\n", line));
        }
        if !example.explanation.is_empty() {
            output.push_str(&format!("   Patterns Applied: {}\n", example.explanation));
        }

        output
    }

    fn monadic_pattern_to_str(pattern: &crate::refactoring::MonadicPattern) -> &'static str {
        match pattern {
            crate::refactoring::MonadicPattern::Option => "Option monad",
            crate::refactoring::MonadicPattern::Result => "Result monad",
            crate::refactoring::MonadicPattern::Future => "Future monad",
            crate::refactoring::MonadicPattern::State => "State monad",
        }
    }

    fn pattern_to_string(&self, pattern: &FunctionalPattern) -> String {
        if let Some(desc) = Self::is_collection_pattern(pattern) {
            return desc.to_string();
        }
        if let Some(desc) = Self::is_control_flow_pattern(pattern) {
            return desc.to_string();
        }
        if let Some(desc) = Self::is_composition_pattern(pattern) {
            return desc.to_string();
        }
        if let FunctionalPattern::Monadic(m) = pattern {
            return Self::monadic_pattern_to_str(m).to_string();
        }
        "Unknown pattern".to_string()
    }
}

pub struct EducationalContentGenerator;

impl EducationalContentGenerator {
    pub fn generate_functional_programming_tips() -> Vec<String> {
        vec![
            "[TIP] Pure functions have no side effects and always return the same output for the same input".to_string(),
            "[TIP] Use map() to transform collections instead of for loops with push()".to_string(),
            "[TIP] Use filter() to select items instead of if statements in loops".to_string(),
            "[TIP] Use fold() to aggregate values instead of mutable accumulators".to_string(),
            "[TIP] Keep I/O operations at the boundaries of your application".to_string(),
            "[TIP] Compose small, focused functions to build complex behavior".to_string(),
            "[TIP] Prefer immutable data structures to prevent unexpected mutations".to_string(),
            "[TIP] Use Result<T, E> for error handling instead of exceptions".to_string(),
            "[TIP] Pattern matching is more expressive than if-else chains".to_string(),
            "[TIP] Property-based testing works great with pure functions".to_string(),
        ]
    }

    pub fn explain_functional_benefits() -> String {
        r#"
## Why Extract Pure Functions?

Pure functions provide several key benefits:

1. **Testability**: Pure functions are trivial to test - just provide input and assert output
2. **Composability**: Pure functions can be easily combined to create complex behavior
3. **Reasoning**: No hidden state or side effects makes code easier to understand
4. **Parallelization**: Pure functions are thread-safe by default
5. **Debugging**: Predictable behavior makes bugs easier to find and fix
6. **Reusability**: Pure functions can be used in any context

## Functional Core / Imperative Shell

This architecture pattern separates your application into:
- **Functional Core**: Pure business logic with no side effects
- **Imperative Shell**: Thin layer handling I/O and orchestration

This gives you the best of both worlds: testable business logic and necessary I/O operations.
"#
        .to_string()
    }
}