//! # Complexity Pattern Detection
//!
//! Classifies complexity hotspots by their primary driver:
//! - **High Nesting**: Cognitive >> Cyclomatic (deep conditionals)
//! - **High Branching**: Many decision points, moderate depth
//! - **Mixed Complexity**: Both nesting and branching high
//! - **Chaotic Structure**: High entropy, inconsistent patterns
//! - **Moderate Complexity**: Approaching thresholds
//!
//! Each pattern gets tailored refactoring recommendations based on
//! the root cause identified through metric ratio analysis.

use serde::{Deserialize, Serialize};

/// Complexity pattern classification based on metric ratios
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ComplexityPattern {
    /// State machine pattern: nested conditionals on enum states
    StateMachine {
        state_transitions: u32,
        match_expression_count: u32,
        cyclomatic: u32,
        cognitive: u32,
        nesting: u32,
    },
    /// Coordinator pattern: orchestrates actions based on state comparisons
    Coordinator {
        action_count: u32,
        comparison_count: u32,
        cyclomatic: u32,
        cognitive: u32,
    },
    /// Dispatcher pattern: Simple routing with many shallow branches (spec 206)
    ///
    /// # Characteristics
    /// - High cyclomatic complexity (>= 10 branches)
    /// - Low nesting (<= 2 levels, flat structure)
    /// - Cognitive/cyclomatic ratio < 2.0 (accounts for `?` operator inflation)
    /// - No action accumulation (unlike Coordinator)
    ///
    /// # Clean vs Polluted Dispatchers
    /// - **Clean**: All arms delegate to helpers, cognitive <= cyclomatic * 1.5
    ///   - Returns None from recommendation generation (no refactoring needed)
    /// - **Polluted**: Some arms have inline logic, cognitive > cyclomatic * 1.5
    ///   - Returns extraction recommendation for inline logic
    ///
    /// # Examples
    /// - Command routers (CLI, HTTP endpoints)
    /// - Event dispatchers with `?` operators
    /// - Match expressions delegating to handlers
    /// - Switch-based handlers
    Dispatcher {
        branch_count: u32,
        cognitive_ratio: f64,
        inline_logic_branches: u32, // Branches exceeding expected cognitive load (0 = clean)
    },
    /// Repetitive validation pattern: many early returns with same structure
    RepetitiveValidation {
        validation_count: u32, // Number of validation checks
        entropy: f64,          // Token entropy (low = repetitive)
        cyclomatic: u32,       // Raw cyclomatic complexity
    },
    /// Deep nesting drives complexity (cognitive >> cyclomatic)
    HighNesting {
        nesting_depth: u32,
        cognitive_score: u32,
        ratio: f64, // cognitive/cyclomatic
    },
    /// Many decision points (high cyclomatic, moderate cognitive)
    HighBranching { branch_count: u32, cyclomatic: u32 },
    /// Both nesting and branching contribute to complexity
    MixedComplexity {
        nesting_depth: u32,
        cyclomatic: u32,
        cognitive: u32,
    },
    /// Inconsistent structure (high entropy)
    ChaoticStructure { entropy: f64, cyclomatic: u32 },
    /// Approaching complexity thresholds
    ModerateComplexity { cyclomatic: u32, cognitive: u32 },
}

/// Signals indicating state machine pattern
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct StateMachineSignals {
    // Existing fields (unchanged)
    #[serde(default)]
    pub transition_count: u32,
    #[serde(default)]
    pub match_expression_count: u32,
    #[serde(default)]
    pub has_enum_match: bool,
    #[serde(default)]
    pub has_state_comparison: bool,
    #[serde(default)]
    pub action_dispatch_count: u32,
    #[serde(default)]
    pub confidence: f64,

    // NEW (spec 203): Arm classification
    #[serde(default)]
    pub primary_match_arms: u32,
    #[serde(default)]
    pub nested_match_arms: u32,
    #[serde(default)]
    pub delegated_arms: u32,
    #[serde(default)]
    pub trivial_arms: u32,
    #[serde(default)]
    pub complex_inline_arms: u32,
    #[serde(default)]
    pub total_inline_lines: u32,
    #[serde(default)]
    pub avg_arm_complexity: f32,
}

/// Signals indicating coordinator pattern
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CoordinatorSignals {
    pub actions: u32,
    pub comparisons: u32,
    pub has_action_accumulation: bool,
    pub has_helper_calls: bool,
    pub confidence: f64,
}

/// Signals indicating repetitive validation pattern
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ValidationSignals {
    pub check_count: u32,
    pub early_return_count: u32,
    pub structural_similarity: f64,
    pub has_validation_name: bool,
    pub confidence: f64,
}

/// Complexity metrics for pattern detection
#[derive(Debug, Clone)]
pub struct ComplexityMetrics {
    pub cyclomatic: u32,
    pub cognitive: u32,
    pub nesting: u32,
    pub entropy_score: Option<f64>,
    pub state_signals: Option<StateMachineSignals>,
    pub coordinator_signals: Option<CoordinatorSignals>,
    pub validation_signals: Option<ValidationSignals>,
}

impl ComplexityPattern {
    /// Detect complexity pattern from metrics.
    ///
    /// **Note (spec 204)**: This method should only be called during analysis/recommendation
    /// generation. Output formatters should read from `UnifiedDebtItem.detected_pattern` instead
    /// of calling this method to ensure consistency across all output formats.
    ///
    /// # Pattern Detection Logic
    ///
    /// 1. **State Machine** (checked first): High-confidence state transition signals
    ///    - Detects functions with nested conditionals on enum states
    ///    - Requires: cyclomatic >= 6, cognitive >= 12, confidence >= 0.7
    ///    - Refactoring: extract state transition functions, create transition map
    ///
    /// 2. **Coordinator** (checked second): Action accumulation and state comparisons
    ///    - Detects functions that orchestrate actions based on state
    ///    - Requires: actions >= 3, comparisons >= 2, confidence >= 0.7
    ///    - Refactoring: extract reconciliation logic into transition map
    ///
    /// 3. **Chaotic Structure**: token_entropy >= 0.45
    ///    - Uses token_entropy (Shannon entropy of code tokens, 0.0-1.0 scale)
    ///    - Threshold 0.45 chosen empirically (typical range: 0.2-0.8)
    ///    - High token entropy indicates inconsistent patterns that make refactoring risky
    ///    - Should be standardized before other refactorings
    ///
    /// 4. **High Nesting**: cognitive/cyclomatic > 3.0 AND nesting >= 4
    ///    - Cognitive dominates cyclomatic (high ratio)
    ///    - Deep nesting (4+ levels) is the primary driver
    ///    - Refactoring: early returns, guard clauses, extract conditionals
    ///
    /// 5. **High Branching**: cyclomatic >= 15 AND ratio < 2.5
    ///    - Many decision points with moderate nesting
    ///    - Refactoring: extract functions, lookup tables, strategy pattern
    ///
    /// 6. **Mixed Complexity**: cyclomatic >= 12 AND cognitive >= 40 AND 2.5 <= ratio <= 3.5
    ///    - Both nesting and branching contribute significantly
    ///    - Refactoring: two-phase approach (flatten then extract)
    ///
    /// 7. **Moderate Complexity**: default
    ///    - Approaching thresholds but not critical
    ///    - Preventive refactoring recommended
    ///
    /// # Examples
    ///
    /// ```
    /// use debtmap::priority::complexity_patterns::{ComplexityPattern, ComplexityMetrics};
    ///
    /// // High nesting example
    /// let metrics = ComplexityMetrics {
    ///     cyclomatic: 12,
    ///     cognitive: 50,  // 4.2x ratio
    ///     nesting: 5,
    ///     entropy_score: Some(0.35),
    ///     state_signals: None,
    ///     coordinator_signals: None,
    ///     validation_signals: None,
    /// };
    /// let pattern = ComplexityPattern::detect(&metrics);
    /// assert!(matches!(pattern, ComplexityPattern::HighNesting { .. }));
    ///
    /// // High branching example (ratio >= 2.0 to avoid Dispatcher classification)
    /// let metrics = ComplexityMetrics {
    ///     cyclomatic: 18,
    ///     cognitive: 40,  // 2.2x ratio (>= 2.0 avoids Dispatcher)
    ///     nesting: 3,
    ///     entropy_score: Some(0.30),
    ///     state_signals: None,
    ///     coordinator_signals: None,
    ///     validation_signals: None,
    /// };
    /// let pattern = ComplexityPattern::detect(&metrics);
    /// assert!(matches!(pattern, ComplexityPattern::HighBranching { .. }));
    /// ```
    pub fn detect(metrics: &ComplexityMetrics) -> Self {
        let ratio = metrics.cognitive as f64 / metrics.cyclomatic.max(1) as f64;

        // Check for repetitive validation pattern FIRST (low entropy + high branching)
        // This prevents validation boilerplate from being misclassified as high complexity
        if let Some(entropy) = metrics.entropy_score
            && is_repetitive_validation(metrics.cyclomatic, entropy, &metrics.validation_signals)
        {
            return ComplexityPattern::RepetitiveValidation {
                validation_count: metrics
                    .validation_signals
                    .as_ref()
                    .map(|v| v.check_count)
                    .unwrap_or(metrics.cyclomatic),
                entropy,
                cyclomatic: metrics.cyclomatic,
            };
        }

        // Check for state machine pattern (highest priority - specific, high-value)
        if let Some(ref state_signals) = metrics.state_signals
            && state_signals.confidence >= 0.7
            && metrics.cyclomatic >= 6
            && metrics.cognitive >= 12
        {
            return ComplexityPattern::StateMachine {
                state_transitions: state_signals.transition_count,
                match_expression_count: state_signals.match_expression_count,
                cyclomatic: metrics.cyclomatic,
                cognitive: metrics.cognitive,
                nesting: metrics.nesting,
            };
        }

        // Check for coordinator pattern (second priority - specific, high-value)
        if let Some(ref coord_signals) = metrics.coordinator_signals
            && coord_signals.confidence >= 0.7
            && coord_signals.actions >= 3
            && coord_signals.comparisons >= 2
        {
            return ComplexityPattern::Coordinator {
                action_count: coord_signals.actions,
                comparison_count: coord_signals.comparisons,
                cyclomatic: metrics.cyclomatic,
                cognitive: metrics.cognitive,
            };
        }

        // Check for dispatcher pattern (after coordinator, before chaotic)
        // Dispatcher (spec 206): high branching with flat structure
        // - cyclomatic >= 10 (many branches)
        // - nesting <= 2 (flat structure - key discriminator)
        // - ratio < 2.0 (not cognitive-dominated; accounts for `?` operator inflation)
        if metrics.cyclomatic >= 10
            && metrics.nesting <= 2
            && ratio < 2.0
            && metrics.coordinator_signals.is_none()
        {
            // Estimate inline logic based on cognitive deviation from expected
            // Clean dispatcher: cognitive ≈ cyclomatic * 1.5 (delegation + `?` operators)
            // Each `?` or simple call adds ~1.0-1.5 cognitive points
            let expected_max_cognitive = (metrics.cyclomatic as f64 * 1.5) as u32;
            let inline_logic_branches = if metrics.cognitive > expected_max_cognitive {
                // Each inline logic section adds ~4 cognitive points beyond delegation
                ((metrics.cognitive - expected_max_cognitive) as f64 / 4.0).ceil() as u32
            } else {
                0
            };

            return ComplexityPattern::Dispatcher {
                branch_count: metrics.cyclomatic,
                cognitive_ratio: ratio,
                inline_logic_branches,
            };
        }

        // Chaotic: high token entropy (check before generic patterns - requires standardization)
        // Note: entropy_score here is token_entropy (Shannon entropy), not effective_complexity
        if let Some(token_entropy) = metrics.entropy_score
            && token_entropy >= 0.45
        {
            return ComplexityPattern::ChaoticStructure {
                entropy: token_entropy,
                cyclomatic: metrics.cyclomatic,
            };
        }

        // High nesting: cognitive dominates
        if ratio > 3.0 && metrics.nesting >= 4 {
            return ComplexityPattern::HighNesting {
                nesting_depth: metrics.nesting,
                cognitive_score: metrics.cognitive,
                ratio,
            };
        }

        // High branching: cyclomatic high, ratio moderate, NOT a flat dispatcher
        // Flat dispatchers (nesting <= 2, ratio < 2.0) are handled above
        // This catches high-branching code with moderate nesting or higher ratio
        if metrics.cyclomatic >= 15 && ratio < 2.5 {
            // Only classify as HighBranching if not a flat dispatcher
            // Flat dispatchers have low nesting (<= 2) and moderate ratio (< 2.0)
            if metrics.nesting >= 2 || ratio >= 2.0 {
                return ComplexityPattern::HighBranching {
                    branch_count: metrics.cyclomatic,
                    cyclomatic: metrics.cyclomatic,
                };
            }
        }

        // Mixed: both high
        if metrics.cyclomatic >= 12 && metrics.cognitive >= 40 && (2.5..=3.5).contains(&ratio) {
            return ComplexityPattern::MixedComplexity {
                nesting_depth: metrics.nesting,
                cyclomatic: metrics.cyclomatic,
                cognitive: metrics.cognitive,
            };
        }

        // Default: moderate
        ComplexityPattern::ModerateComplexity {
            cyclomatic: metrics.cyclomatic,
            cognitive: metrics.cognitive,
        }
    }

    /// Get a human-readable description of the pattern
    pub fn description(&self) -> &'static str {
        match self {
            ComplexityPattern::StateMachine { .. } => "State machine with transition logic",
            ComplexityPattern::Coordinator { .. } => {
                "Coordinator orchestrating state-based actions"
            }
            ComplexityPattern::Dispatcher { .. } => "Simple dispatcher with shallow branching",
            ComplexityPattern::RepetitiveValidation { .. } => "Repetitive validation boilerplate",
            ComplexityPattern::HighNesting { .. } => "Deep nesting drives complexity",
            ComplexityPattern::HighBranching { .. } => "Many decision points",
            ComplexityPattern::MixedComplexity { .. } => "Both nesting and branching high",
            ComplexityPattern::ChaoticStructure { .. } => "Inconsistent structure patterns",
            ComplexityPattern::ModerateComplexity { .. } => "Approaching complexity thresholds",
        }
    }
}

/// Determine if metrics indicate repetitive validation pattern
fn is_repetitive_validation(
    cyclomatic: u32,
    entropy: f64,
    validation_signals: &Option<ValidationSignals>,
) -> bool {
    // Low entropy + high branching is primary signal
    let has_low_entropy_high_branching = entropy < 0.35 && cyclomatic >= 10;

    if !has_low_entropy_high_branching {
        return false;
    }

    // Additional validation signals strengthen confidence
    if let Some(signals) = validation_signals {
        // Require majority of branches to be early returns
        let early_return_ratio = signals.early_return_count as f64 / cyclomatic as f64;

        if early_return_ratio < 0.6 {
            return false;
        }

        // High structural similarity (measured by AST pattern matching)
        if signals.structural_similarity < 0.7 {
            return false;
        }

        true
    } else {
        // Without validation signals, we can't confirm it's a validation pattern
        // Return false to avoid false positives
        false
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn detect_high_nesting_pattern() {
        let metrics = ComplexityMetrics {
            cyclomatic: 12,
            cognitive: 50, // 4.2x ratio
            nesting: 5,
            entropy_score: Some(0.35),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(matches!(pattern, ComplexityPattern::HighNesting { .. }));

        if let ComplexityPattern::HighNesting {
            nesting_depth,
            cognitive_score,
            ratio,
        } = pattern
        {
            assert_eq!(nesting_depth, 5);
            assert_eq!(cognitive_score, 50);
            assert!((ratio - 4.17).abs() < 0.01);
        }
    }

    #[test]
    fn detect_high_branching_pattern() {
        // High branching requires: cyclomatic >= 15, ratio < 2.5, nesting >= 2 OR ratio >= 2.0
        // With spec 206, flat structures (nesting <= 2) with low ratio go to Dispatcher
        let metrics = ComplexityMetrics {
            cyclomatic: 18,
            cognitive: 35, // ratio: 1.94
            nesting: 3,    // Spec 206: need nesting > 2 to avoid Dispatcher
            entropy_score: Some(0.30),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(matches!(pattern, ComplexityPattern::HighBranching { .. }));
    }

    #[test]
    fn detect_mixed_complexity_pattern() {
        let metrics = ComplexityMetrics {
            cyclomatic: 15,
            cognitive: 45, // 3.0x ratio
            nesting: 3,
            entropy_score: Some(0.32),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(matches!(pattern, ComplexityPattern::MixedComplexity { .. }));
    }

    #[test]
    fn detect_chaotic_structure_pattern() {
        let metrics = ComplexityMetrics {
            cyclomatic: 12,
            cognitive: 30,
            nesting: 3,
            entropy_score: Some(0.50), // High entropy
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(matches!(
            pattern,
            ComplexityPattern::ChaoticStructure { .. }
        ));
    }

    #[test]
    fn detect_moderate_complexity_pattern() {
        // Moderate complexity: not matching any specific pattern
        // Spec 206: cyclomatic >= 10, nesting <= 2, ratio < 2.0 => Dispatcher
        // Use lower cyclomatic or higher nesting to get ModerateComplexity
        let metrics = ComplexityMetrics {
            cyclomatic: 9, // Below Dispatcher threshold (10)
            cognitive: 18,
            nesting: 2,
            entropy_score: Some(0.30),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(matches!(
            pattern,
            ComplexityPattern::ModerateComplexity { .. }
        ));
    }

    #[test]
    fn chaotic_takes_precedence_over_nesting() {
        // High nesting metrics BUT high entropy
        let metrics = ComplexityMetrics {
            cyclomatic: 12,
            cognitive: 50,
            nesting: 5,
            entropy_score: Some(0.48), // High entropy takes precedence
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::ChaoticStructure { .. }),
            "Chaotic structure should be detected before high nesting"
        );
    }

    #[test]
    fn ratio_boundary_conditions() {
        // Exactly at high nesting threshold
        let metrics = ComplexityMetrics {
            cyclomatic: 10,
            cognitive: 30, // Exactly 3.0x
            nesting: 4,
            entropy_score: Some(0.30),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        // ratio > 3.0 requires strictly greater, so this should NOT be HighNesting
        assert!(
            !matches!(pattern, ComplexityPattern::HighNesting { .. }),
            "Exactly 3.0 ratio should not trigger HighNesting (requires > 3.0)"
        );
    }

    #[test]
    fn handles_zero_cyclomatic() {
        // Edge case: cyclomatic = 0 (shouldn't happen but test defensive coding)
        let metrics = ComplexityMetrics {
            cyclomatic: 0,
            cognitive: 10,
            nesting: 2,
            entropy_score: Some(0.30),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        // Should use max(1) to avoid division by zero
        assert!(matches!(
            pattern,
            ComplexityPattern::ModerateComplexity { .. }
        ));
    }

    #[test]
    fn detect_state_machine_pattern() {
        let metrics = ComplexityMetrics {
            cyclomatic: 9,
            cognitive: 16,
            nesting: 4,
            entropy_score: Some(0.32),
            state_signals: Some(StateMachineSignals {
                transition_count: 3,
                match_expression_count: 2,
                has_enum_match: true,
                has_state_comparison: true,
                action_dispatch_count: 4,
                confidence: 0.85,
                ..Default::default()
            }),
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(matches!(pattern, ComplexityPattern::StateMachine { .. }));

        if let ComplexityPattern::StateMachine {
            state_transitions, ..
        } = pattern
        {
            assert_eq!(state_transitions, 3);
        }
    }

    #[test]
    fn detect_coordinator_pattern() {
        let metrics = ComplexityMetrics {
            cyclomatic: 8,
            cognitive: 14,
            nesting: 3,
            entropy_score: Some(0.28),
            state_signals: None,
            coordinator_signals: Some(CoordinatorSignals {
                actions: 4,
                comparisons: 2,
                has_action_accumulation: true,
                has_helper_calls: true,
                confidence: 0.80,
            }),
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(matches!(pattern, ComplexityPattern::Coordinator { .. }));
    }

    #[test]
    fn state_pattern_takes_precedence_over_nesting() {
        // High nesting metrics BUT state machine signals
        let metrics = ComplexityMetrics {
            cyclomatic: 12,
            cognitive: 50,
            nesting: 5,
            entropy_score: Some(0.35),
            state_signals: Some(StateMachineSignals {
                transition_count: 4,
                match_expression_count: 3,
                has_enum_match: true,
                has_state_comparison: true,
                action_dispatch_count: 6,
                confidence: 0.90,
                ..Default::default()
            }),
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::StateMachine { .. }),
            "State machine pattern should take precedence over generic high nesting"
        );
    }

    #[test]
    fn pattern_descriptions() {
        assert_eq!(
            ComplexityPattern::StateMachine {
                state_transitions: 3,
                match_expression_count: 2,
                cyclomatic: 9,
                cognitive: 16,
                nesting: 4,
            }
            .description(),
            "State machine with transition logic"
        );

        assert_eq!(
            ComplexityPattern::Coordinator {
                action_count: 4,
                comparison_count: 2,
                cyclomatic: 8,
                cognitive: 14,
            }
            .description(),
            "Coordinator orchestrating state-based actions"
        );

        assert_eq!(
            ComplexityPattern::HighNesting {
                nesting_depth: 5,
                cognitive_score: 50,
                ratio: 4.0
            }
            .description(),
            "Deep nesting drives complexity"
        );

        assert_eq!(
            ComplexityPattern::HighBranching {
                branch_count: 18,
                cyclomatic: 18
            }
            .description(),
            "Many decision points"
        );
    }

    #[test]
    fn detect_repetitive_validation_pattern() {
        let metrics = ComplexityMetrics {
            cyclomatic: 20,
            cognitive: 25,
            nesting: 1,
            entropy_score: Some(0.28),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: Some(ValidationSignals {
                check_count: 20,
                early_return_count: 20,
                structural_similarity: 0.95,
                has_validation_name: true,
                confidence: 0.9,
            }),
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(matches!(
            pattern,
            ComplexityPattern::RepetitiveValidation { .. }
        ));

        if let ComplexityPattern::RepetitiveValidation {
            validation_count,
            entropy,
            cyclomatic,
        } = pattern
        {
            assert_eq!(validation_count, 20);
            assert_eq!(cyclomatic, 20);
            assert!((entropy - 0.28).abs() < 0.01);
        }
    }

    #[test]
    fn validation_pattern_takes_precedence_over_high_branching() {
        // High branching metrics BUT repetitive validation signals
        let metrics = ComplexityMetrics {
            cyclomatic: 18,
            cognitive: 20,
            nesting: 1,
            entropy_score: Some(0.30),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: Some(ValidationSignals {
                check_count: 18,
                early_return_count: 18,
                structural_similarity: 0.92,
                has_validation_name: true,
                confidence: 0.85,
            }),
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::RepetitiveValidation { .. }),
            "Repetitive validation should take precedence over high branching"
        );
    }

    #[test]
    fn high_entropy_prevents_validation_detection() {
        // High branching but HIGH entropy (varied logic)
        let metrics = ComplexityMetrics {
            cyclomatic: 20,
            cognitive: 45,
            nesting: 2,
            entropy_score: Some(0.55),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            !matches!(pattern, ComplexityPattern::RepetitiveValidation { .. }),
            "High entropy should prevent validation pattern detection"
        );
    }

    // Tests for dispatcher pattern (spec 189, spec 206)

    #[test]
    fn detect_clean_dispatcher_pattern() {
        // Spec 206: Clean dispatcher with ? operators
        // cyclo=26, cognitive=40, ratio=1.54 (NOT < 0.5, but flat and delegation-style)
        let metrics = ComplexityMetrics {
            cyclomatic: 26,
            cognitive: 30, // Within expected range: 26 * 1.5 = 39
            nesting: 1,    // Flat structure (key for spec 206)
            entropy_score: Some(0.30),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(
                pattern,
                ComplexityPattern::Dispatcher {
                    inline_logic_branches: 0,
                    ..
                }
            ),
            "Should detect as clean Dispatcher, got: {:?}",
            pattern
        );

        if let ComplexityPattern::Dispatcher {
            branch_count,
            cognitive_ratio,
            inline_logic_branches,
        } = pattern
        {
            assert_eq!(branch_count, 26);
            assert!((cognitive_ratio - 1.15).abs() < 0.1);
            assert_eq!(inline_logic_branches, 0); // Clean dispatcher
        }
    }

    #[test]
    fn detect_dispatcher_with_question_mark_inflation() {
        // Spec 206 example: write_section with 26 cyclomatic, 40 cognitive
        // Ratio 1.54 - previously failed < 0.5 check, now passes < 2.0
        let metrics = ComplexityMetrics {
            cyclomatic: 26,
            cognitive: 40,
            nesting: 1, // Flat structure
            entropy_score: Some(0.30),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::Dispatcher { .. }),
            "write_section should be classified as Dispatcher, got: {:?}",
            pattern
        );

        if let ComplexityPattern::Dispatcher {
            cognitive_ratio,
            inline_logic_branches,
            ..
        } = pattern
        {
            assert!((cognitive_ratio - 1.54).abs() < 0.1);
            // Expected max: 26 * 1.5 = 39, actual: 40, excess: 1, branches: ceil(1/4) = 1
            assert!(
                inline_logic_branches <= 1,
                "Should have minimal inline logic, got: {}",
                inline_logic_branches
            );
        }
    }

    #[test]
    fn detect_polluted_dispatcher_pattern() {
        // Dispatcher with some inline logic
        // Spec 206: requires ratio < 2.0
        let metrics = ComplexityMetrics {
            cyclomatic: 26,
            cognitive: 50, // ratio: 1.92 (< 2.0), expected max: 26 * 1.5 = 39
            nesting: 1,    // Flat structure
            entropy_score: Some(0.35),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);

        match pattern {
            ComplexityPattern::Dispatcher {
                inline_logic_branches,
                ..
            } => {
                // Expected max: 39, actual: 50, excess: 11, branches: ceil(11/4) = 3
                assert!(inline_logic_branches > 0, "Should detect inline logic");
            }
            _ => panic!("Should detect as Dispatcher, got: {:?}", pattern),
        }
    }

    #[test]
    fn detect_dispatcher_with_inline_logic() {
        // Dispatcher with inline logic: higher cognitive than expected
        // Spec 206: requires ratio < 2.0, expected_max = cyclomatic * 1.5
        let metrics = ComplexityMetrics {
            cyclomatic: 30,
            cognitive: 55, // ratio: 1.83 (< 2.0), expected max: 30 * 1.5 = 45
            nesting: 2,
            entropy_score: Some(0.25),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::Dispatcher { .. }),
            "Should detect as Dispatcher, got: {:?}",
            pattern
        );

        if let ComplexityPattern::Dispatcher {
            inline_logic_branches,
            ..
        } = pattern
        {
            assert!(inline_logic_branches > 0); // Has inline logic
            // Expected: 45, actual: 55, diff: 10, branches: ceil(10/4) = 3
            assert_eq!(inline_logic_branches, 3);
        }
    }

    #[test]
    fn coordinator_not_misclassified_as_dispatcher() {
        // Coordinator with low ratio should not become dispatcher
        let metrics = ComplexityMetrics {
            cyclomatic: 20,
            cognitive: 10, // ratio: 0.50 (borderline)
            nesting: 3,
            entropy_score: Some(0.28),
            state_signals: None,
            coordinator_signals: Some(CoordinatorSignals {
                actions: 5,
                comparisons: 3,
                has_action_accumulation: true,
                has_helper_calls: true,
                confidence: 0.8,
            }),
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::Coordinator { .. }),
            "Coordinator signals should take precedence over dispatcher"
        );
    }

    #[test]
    fn high_nesting_not_dispatcher() {
        // Spec 206: High nesting should NOT be classified as Dispatcher
        let metrics = ComplexityMetrics {
            cyclomatic: 20,
            cognitive: 60, // High cognitive from nesting
            nesting: 4,    // Deep nesting (> 2)
            entropy_score: Some(0.30),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);

        assert!(
            !matches!(pattern, ComplexityPattern::Dispatcher { .. }),
            "High nesting should not be Dispatcher, got: {:?}",
            pattern
        );
    }

    #[test]
    fn deep_nesting_not_misclassified_as_dispatcher() {
        // Deep nesting with high ratio should not be dispatcher
        let metrics = ComplexityMetrics {
            cyclomatic: 20,
            cognitive: 80, // ratio: 4.0 (very high)
            nesting: 6,
            entropy_score: Some(0.32),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::HighNesting { .. }),
            "Deep nesting should be detected, not dispatcher"
        );
    }

    #[test]
    fn dispatcher_requires_minimum_cyclomatic() {
        // Spec 206: cyclomatic >= 10 required for dispatcher
        let metrics = ComplexityMetrics {
            cyclomatic: 9, // Below threshold (10)
            cognitive: 3,  // Low ratio
            nesting: 1,    // Flat structure
            entropy_score: Some(0.28),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            !matches!(pattern, ComplexityPattern::Dispatcher { .. }),
            "Dispatcher requires cyclomatic >= 10, got: {:?}",
            pattern
        );
    }

    #[test]
    fn dispatcher_requires_flat_structure() {
        // Spec 206: nesting <= 2 required for dispatcher
        let metrics = ComplexityMetrics {
            cyclomatic: 20,
            cognitive: 25, // Moderate ratio
            nesting: 3,    // Too deep for dispatcher
            entropy_score: Some(0.25),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            !matches!(pattern, ComplexityPattern::Dispatcher { .. }),
            "Dispatcher requires nesting <= 2, got: {:?}",
            pattern
        );
    }

    #[test]
    fn dispatcher_requires_moderate_ratio() {
        // Spec 206: ratio < 2.0 required for dispatcher
        let metrics = ComplexityMetrics {
            cyclomatic: 15,
            cognitive: 45, // ratio: 3.0 (> 2.0)
            nesting: 1,    // Flat structure
            entropy_score: Some(0.25),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            !matches!(pattern, ComplexityPattern::Dispatcher { .. }),
            "Dispatcher requires ratio < 2.0, got: {:?}",
            pattern
        );
    }

    #[test]
    fn dispatcher_pattern_description() {
        let pattern = ComplexityPattern::Dispatcher {
            branch_count: 20,
            cognitive_ratio: 0.30,
            inline_logic_branches: 0,
        };

        assert_eq!(
            pattern.description(),
            "Simple dispatcher with shallow branching"
        );
    }

    #[test]
    fn dispatcher_precedence_order() {
        // Dispatcher check comes after coordinator but before chaotic
        // Low entropy + high branching + low ratio + flat nesting -> should be dispatcher
        let metrics = ComplexityMetrics {
            cyclomatic: 20,
            cognitive: 25,             // ratio: 1.25 (within spec 206 range)
            nesting: 1,                // Flat structure (required for dispatcher)
            entropy_score: Some(0.25), // Low entropy
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::Dispatcher { .. }),
            "Dispatcher should be detected before high branching, got: {:?}",
            pattern
        );
    }

    #[test]
    fn high_branching_still_detected_for_non_flat() {
        // Spec 206: HighBranching should still be detected for non-flat high-branching code
        let metrics = ComplexityMetrics {
            cyclomatic: 20,
            cognitive: 35, // ratio: 1.75
            nesting: 3,    // Too deep for dispatcher
            entropy_score: Some(0.25),
            state_signals: None,
            coordinator_signals: None,
            validation_signals: None,
        };

        let pattern = ComplexityPattern::detect(&metrics);
        assert!(
            matches!(pattern, ComplexityPattern::HighBranching { .. }),
            "High branching should be detected for non-flat code, got: {:?}",
            pattern
        );
    }
}
