ferrous-forge 1.9.6

System-wide Rust development standards enforcer
Documentation
//! AI strategy generation for violation fix recommendations
//!
//! This module contains functions for generating intelligent fix strategies based on
//! violation analysis patterns, code pattern identification, and AI instruction generation
//! to help developers resolve Ferrous Forge violations effectively.

use super::types::{
    AIInstructions, ArchitecturalStyle, CodePatterns, ErrorPattern, FixStrategy, Pattern,
    ViolationAnalysis,
};
use crate::validation::ViolationType;

/// Generate fix strategies from violation analyses
pub fn generate_fix_strategies(analyses: &[ViolationAnalysis]) -> Vec<FixStrategy> {
    let mut strategies = Vec::new();
    let mut violation_counts = std::collections::HashMap::new();

    for analysis in analyses {
        *violation_counts
            .entry(&analysis.violation.violation_type)
            .or_insert(0) += 1;
    }

    for (violation_type, count) in violation_counts {
        strategies.push(create_strategy(violation_type.clone(), count));
    }

    strategies
}

fn create_strategy(violation_type: ViolationType, count: usize) -> FixStrategy {
    match violation_type {
        ViolationType::UnwrapInProduction => create_unwrap_strategy(violation_type, count),
        ViolationType::UnderscoreBandaid => create_underscore_strategy(violation_type, count),
        ViolationType::FunctionTooLarge => create_function_refactor_strategy(violation_type, count),
        ViolationType::FileTooLarge => create_file_refactor_strategy(violation_type, count),
        ViolationType::WrongEdition
        | ViolationType::OldRustVersion
        | ViolationType::LockedSetting => create_locked_setting_strategy(violation_type, count),
        _ => create_generic_strategy(violation_type, count),
    }
}

/// Create strategy for locked setting violations — humans only, never AI-fixable
fn create_locked_setting_strategy(violation_type: ViolationType, _count: usize) -> FixStrategy {
    FixStrategy {
        violation_type,
        strategy_name: "Escalate to human — locked project setting".to_string(),
        description: "This violation involves a setting locked by .ferrous-forge/config.toml. \
             AI agents MUST NOT attempt to resolve this by changing Cargo.toml."
            .to_string(),
        implementation_steps: vec![
            "DO NOT change edition or rust-version in Cargo.toml.".to_string(),
            "DO NOT change required_edition or required_rust_version in config.".to_string(),
            "Escalate to a human project owner for guidance.".to_string(),
            "Ensure Cargo.toml values match the locked config values.".to_string(),
        ],
        estimated_effort: "Human intervention required".to_string(),
        risk_level: "High — changing locked settings can break CI and team standards".to_string(),
    }
}

/// Create strategy for unwrap violations
fn create_unwrap_strategy(violation_type: ViolationType, count: usize) -> FixStrategy {
    FixStrategy {
        violation_type,
        strategy_name: "Replace unwrap with proper error handling".to_string(),
        description: format!(
            "Replace {} instances of .unwrap() with ? operator or proper error handling",
            count
        ),
        implementation_steps: vec![
            "Identify function return type".to_string(),
            "If Result type, replace .unwrap() with ?".to_string(),
            "If not, change return type to Result".to_string(),
            "Update function callers".to_string(),
        ],
        estimated_effort: if count < 10 { "Low" } else { "Medium" }.to_string(),
        risk_level: "Low".to_string(),
    }
}

/// Create strategy for underscore violations
fn create_underscore_strategy(violation_type: ViolationType, count: usize) -> FixStrategy {
    FixStrategy {
        violation_type,
        strategy_name: "Remove underscore prefixes".to_string(),
        description: format!("Fix {} underscore parameter warnings properly", count),
        implementation_steps: vec![
            "Identify unused parameters".to_string(),
            "Either use the parameter or remove it".to_string(),
            "Update function signatures if needed".to_string(),
        ],
        estimated_effort: "Low".to_string(),
        risk_level: "Low".to_string(),
    }
}

/// Create strategy for large function violations
fn create_function_refactor_strategy(violation_type: ViolationType, count: usize) -> FixStrategy {
    FixStrategy {
        violation_type,
        strategy_name: "Refactor large functions".to_string(),
        description: format!("Break down {} large functions into smaller ones", count),
        implementation_steps: vec![
            "Identify logical sections".to_string(),
            "Extract helper functions".to_string(),
            "Improve code organization".to_string(),
        ],
        estimated_effort: "High".to_string(),
        risk_level: "Medium".to_string(),
    }
}

/// Create strategy for large file violations
fn create_file_refactor_strategy(violation_type: ViolationType, count: usize) -> FixStrategy {
    FixStrategy {
        violation_type,
        strategy_name: "Split large files into modules".to_string(),
        description: format!("Modularize {} large files", count),
        implementation_steps: vec![
            "Identify logical components".to_string(),
            "Create module structure".to_string(),
            "Move code to appropriate modules".to_string(),
            "Update imports".to_string(),
        ],
        estimated_effort: "High".to_string(),
        risk_level: "Medium".to_string(),
    }
}

/// Create generic strategy for other violations
fn create_generic_strategy(violation_type: ViolationType, count: usize) -> FixStrategy {
    FixStrategy {
        violation_type,
        strategy_name: "Generic fix".to_string(),
        description: format!("Fix {} violations", count),
        implementation_steps: vec!["Analyze violation".to_string(), "Apply fix".to_string()],
        estimated_effort: "Medium".to_string(),
        risk_level: "Low".to_string(),
    }
}

/// Generate AI instructions for fixing violations
pub fn generate_ai_instructions(
    analyses: &[ViolationAnalysis],
    _strategies: &[FixStrategy],
) -> AIInstructions {
    let summary = create_analysis_summary(analyses);
    let prioritized_fixes = categorize_and_prioritize_fixes(analyses);
    let architectural_recommendations = get_architectural_recommendations();
    let code_quality_improvements = get_code_quality_improvements();

    AIInstructions {
        summary,
        prioritized_fixes,
        architectural_recommendations,
        code_quality_improvements,
    }
}

/// Create a summary of the analysis results
fn create_analysis_summary(analyses: &[ViolationAnalysis]) -> String {
    format!(
        "Analyzed {} violations. {} are AI-fixable with varying complexity.",
        analyses.len(),
        analyses.iter().filter(|a| a.ai_fixable).count()
    )
}

/// Categorize and prioritize fixes by complexity
fn categorize_and_prioritize_fixes(analyses: &[ViolationAnalysis]) -> Vec<String> {
    let mut trivial_fixes = Vec::new();
    let mut simple_fixes = Vec::new();
    let mut moderate_fixes = Vec::new();

    for analysis in analyses {
        if !analysis.ai_fixable {
            continue;
        }

        let fix_desc = format!(
            "Fix {:?} at {}:{} (confidence: {:.0}%)",
            analysis.violation.violation_type,
            analysis.violation.file.display(),
            analysis.violation.line,
            analysis.confidence_score * 100.0
        );

        match analysis.fix_complexity {
            super::types::FixComplexity::Trivial => trivial_fixes.push(fix_desc),
            super::types::FixComplexity::Simple => simple_fixes.push(fix_desc),
            super::types::FixComplexity::Moderate => moderate_fixes.push(fix_desc),
            _ => {}
        }
    }

    let mut prioritized_fixes = Vec::new();
    prioritized_fixes.extend(trivial_fixes);
    prioritized_fixes.extend(simple_fixes);
    prioritized_fixes.extend(moderate_fixes);

    prioritized_fixes
}

/// Get architectural recommendations
fn get_architectural_recommendations() -> Vec<String> {
    vec![
        "Consider adopting consistent error handling patterns".to_string(),
        "Modularize large files to improve maintainability".to_string(),
        "Extract complex logic into well-tested utility functions".to_string(),
    ]
}

/// Get code quality improvement suggestions
fn get_code_quality_improvements() -> Vec<String> {
    vec![
        "Add comprehensive documentation".to_string(),
        "Increase test coverage".to_string(),
        "Implement CI/CD checks for code standards".to_string(),
    ]
}

/// Identify code patterns in the given content
pub fn identify_code_patterns(content: &str) -> CodePatterns {
    let architectural_style = detect_architectural_style(content);
    let error_patterns = detect_error_patterns(content);
    let common_patterns = detect_common_patterns(content);

    CodePatterns {
        architectural_style,
        error_patterns,
        common_patterns,
    }
}

fn detect_architectural_style(content: &str) -> ArchitecturalStyle {
    if content.contains("mod ") && content.matches("mod ").count() > 5 {
        ArchitecturalStyle::Modular
    } else if content.contains("async fn") && content.contains("tokio") {
        ArchitecturalStyle::EventDriven
    } else if content.contains("layer") || content.contains("Layer") {
        ArchitecturalStyle::Layered
    } else {
        ArchitecturalStyle::Unknown
    }
}

fn detect_error_patterns(content: &str) -> Vec<ErrorPattern> {
    let mut patterns = Vec::new();

    if content.contains(".unwrap()") {
        patterns.push(ErrorPattern::UnwrapUsage);
    }
    if content.contains(".expect(") {
        patterns.push(ErrorPattern::ExpectUsage);
    }
    if content.contains("panic!") {
        patterns.push(ErrorPattern::PanicUsage);
    }
    if content.contains("let _ =") {
        patterns.push(ErrorPattern::IgnoredError);
    }
    if content.contains("?") {
        patterns.push(ErrorPattern::PropagatedError);
    }

    patterns
}

fn detect_common_patterns(content: &str) -> Vec<Pattern> {
    let mut patterns = Vec::new();

    let builder_count = content.matches("Builder").count();
    if builder_count > 0 {
        patterns.push(Pattern {
            name: "Builder Pattern".to_string(),
            occurrences: builder_count,
            locations: vec![],
        });
    }

    let factory_count = content.matches("Factory").count() + content.matches("::new(").count();
    if factory_count > 0 {
        patterns.push(Pattern {
            name: "Factory Pattern".to_string(),
            occurrences: factory_count,
            locations: vec![],
        });
    }

    patterns
}