//! Optimization suggestion generation.
//!
//! Analyzes cost signals and plan steps to generate actionable
//! optimization suggestions for the user.

use super::types::*;

/// Generate optimization suggestions based on cost signals and plan steps.
///
/// Each suggestion includes a kind, human-readable message, and priority.
/// Suggestions are ordered by priority (high first).
pub fn generate_suggestions(
    signals: &CostSignals,
    steps: &[PlanStep],
) -> Vec<OptimizationSuggestion> {
    let mut suggestions = Vec::new();

    // Suggest adding filters for unfiltered scans in multi-table queries
    if signals.table_count > 1 && !signals.unfiltered_scans.is_empty() {
        for table in &signals.unfiltered_scans {
            suggestions.push(OptimizationSuggestion {
                kind: SuggestionType::AddFilter,
                message: format!(
                    "Consider adding a WHERE clause filter on table '{table}' to reduce rows processed"
                ),
                priority: SuggestionPriority::Medium,
            });
        }
    }

    // Suggest adding LIMIT for multi-table queries without limit
    if !signals.has_limit && signals.table_count > 1 {
        suggestions.push(OptimizationSuggestion {
            kind: SuggestionType::AddLimit,
            message: "Consider adding a LIMIT clause to prevent large result sets".to_string(),
            priority: SuggestionPriority::Low,
        });
    }

    // Suggest avoiding cross joins
    if signals.has_cross_join {
        suggestions.push(OptimizationSuggestion {
            kind: SuggestionType::AvoidCrossJoin,
            message: "CROSS JOIN produces a cartesian product. Consider using an INNER JOIN with an ON clause instead".to_string(),
            priority: SuggestionPriority::High,
        });
    }

    // Suggest replacing SELECT *
    if signals.uses_select_star {
        suggestions.push(OptimizationSuggestion {
            kind: SuggestionType::RemoveSelectStar,
            message:
                "Replace SELECT * with specific column names to reduce data transfer and improve clarity"
                    .to_string(),
            priority: SuggestionPriority::Medium,
        });
    }

    // Suggest removing redundant DISTINCT
    if signals.has_distinct && has_group_by(steps) {
        suggestions.push(OptimizationSuggestion {
            kind: SuggestionType::RemoveRedundantDistinct,
            message: "DISTINCT may be redundant when GROUP BY is present, as GROUP BY already produces unique groups".to_string(),
            priority: SuggestionPriority::Low,
        });
    }

    // Sort by priority (High first)
    suggestions.sort_by(|a, b| priority_rank(&a.priority).cmp(&priority_rank(&b.priority)));

    suggestions
}

/// Check if any step contains a GROUP BY.
fn has_group_by(steps: &[PlanStep]) -> bool {
    for step in steps {
        match &step.operation {
            PlanOperation::Aggregate { group_by, .. } if !group_by.is_empty() => return true,
            PlanOperation::Subquery { inner_steps, .. } => {
                if has_group_by(inner_steps) {
                    return true;
                }
            }
            _ => {}
        }
    }
    false
}

/// Convert priority to a numeric rank for sorting (lower = higher priority).
fn priority_rank(priority: &SuggestionPriority) -> u8 {
    match priority {
        SuggestionPriority::High => 0,
        SuggestionPriority::Medium => 1,
        SuggestionPriority::Low => 2,
    }
}
