//! Feature Configuration for Progressive ML Feature Engineering
//!
//! This module defines the feature set configuration across Wave 19 phases:
//! - Wave A: 26 features (real-time inference baseline)
//! - Wave B: 36 features (adds alternative bars + volume features)
//! - Wave C: 201 features (adds fractional diff + meta-labeling)
//! - Wave D: 225 features (adds regime detection + adaptive strategies)
//!
//! ## Architecture
//!
//! `FeatureConfig` provides a single source of truth for feature extraction
//! across both training (`DbnSequenceLoader`) and inference (`ProductionFeatureExtractorAdapter`).
//! This eliminates the previous padding bug (256 features via 25x repetition).
//!
//! ## Usage
//!
//! ```rust
//! use ml::features::config::{FeatureConfig, FeaturePhase};
//!
//! // Wave A: 26 features (baseline)
//! let config = FeatureConfig::wave_a();
//! assert_eq!(config.feature_count(), 26);
//!
//! // Wave B: 36 features (alternative bars)
//! let config = FeatureConfig::wave_b();
//! assert_eq!(config.feature_count(), 36);
//!
//! // Wave C: 201 features (advanced)
//! let config = FeatureConfig::wave_c();
//! assert_eq!(config.feature_count(), 201);
//!
//! // Wave D: 225 features (regime detection)
//! let config = FeatureConfig::wave_d();
//! assert_eq!(config.feature_count(), 225);
//! ```

use serde::{Deserialize, Serialize};

/// Feature category classification for Wave D features
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum FeatureCategory {
    /// OHLCV baseline features
    OHLCV,
    /// Technical indicators
    TechnicalIndicators,
    /// Microstructure features
    Microstructure,
    /// Regime detection features
    RegimeDetection,
    /// Adaptive strategy features
    AdaptiveStrategy,
}

/// Individual feature definition with index, name, and category
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Feature {
    /// Feature index (0-224 for Wave D)
    pub index: usize,
    /// Feature name
    pub name: String,
    /// Feature category
    pub category: FeatureCategory,
}

impl Feature {
    /// Create a new feature definition
    pub const fn new(index: usize, _name: &'static str, category: FeatureCategory) -> Self {
        Self {
            index,
            name: String::new(), // Will be set via constructor
            category,
        }
    }
}

/// Wave D feature definitions (indices 201-224)
///
/// This provides the detailed specification for all 24 Wave D features
/// that extend Wave C's 201 features to reach 225 total features.
pub fn wave_d_features() -> Vec<Feature> {
    vec![
        // CUSUM Statistics (indices 201-210, 10 features)
        Feature {
            index: 201,
            name: "cusum_s_plus_normalized".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 202,
            name: "cusum_s_minus_normalized".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 203,
            name: "cusum_break_indicator".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 204,
            name: "cusum_direction".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 205,
            name: "cusum_time_since_break".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 206,
            name: "cusum_frequency".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 207,
            name: "cusum_positive_count".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 208,
            name: "cusum_negative_count".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 209,
            name: "cusum_intensity".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 210,
            name: "cusum_drift_ratio".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        // ADX & Directional Indicators (indices 211-215, 5 features)
        Feature {
            index: 211,
            name: "adx".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 212,
            name: "plus_di".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 213,
            name: "minus_di".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 214,
            name: "dx".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 215,
            name: "trend_classification".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        // Regime Transition Probabilities (indices 216-220, 5 features)
        Feature {
            index: 216,
            name: "regime_stability".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 217,
            name: "most_likely_next_regime".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 218,
            name: "regime_entropy".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 219,
            name: "regime_expected_duration".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        Feature {
            index: 220,
            name: "regime_change_probability".to_owned(),
            category: FeatureCategory::RegimeDetection,
        },
        // Adaptive Strategy Metrics (indices 221-224, 4 features)
        Feature {
            index: 221,
            name: "position_multiplier".to_owned(),
            category: FeatureCategory::AdaptiveStrategy,
        },
        Feature {
            index: 222,
            name: "stop_loss_multiplier".to_owned(),
            category: FeatureCategory::AdaptiveStrategy,
        },
        Feature {
            index: 223,
            name: "regime_conditioned_sharpe".to_owned(),
            category: FeatureCategory::AdaptiveStrategy,
        },
        Feature {
            index: 224,
            name: "risk_budget_utilization".to_owned(),
            category: FeatureCategory::AdaptiveStrategy,
        },
    ]
}

/// Feature extraction configuration for Wave 19 progressive engineering
///
/// Tracks which feature groups are enabled across Wave A/B/C/D phases.
/// Used by both training (`DbnSequenceLoader`) and inference (`ProductionFeatureExtractorAdapter`).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeatureConfig {
    /// Feature engineering phase (Wave A/B/C/D)
    pub phase: FeaturePhase,

    /// Enable baseline OHLCV features (5 features)
    pub enable_ohlcv: bool,

    /// Enable technical indicators (21 features)
    /// Wave A: RSI, MACD, Bollinger, ATR, ADX, CCI, Stochastic, EMAs, Williams %R, ROC, Ultimate Osc, OBV, MFI, VWAP
    pub enable_technical_indicators: bool,

    /// Enable microstructure features (3 features)
    /// Wave A: Amihud Illiquidity, Roll Measure, Corwin-Schultz Spread
    pub enable_microstructure: bool,

    /// Enable alternative bar features (10 features)
    /// Wave B: Dollar bars, Volume bars, Tick bars, Run bars, Imbalance bars
    pub enable_alternative_bars: bool,

    /// Enable barrier optimization features (variable)
    /// Wave B: Triple-barrier labels, Meta-labeling
    pub enable_barrier_optimization: bool,

    /// Enable fractional differentiation features (variable)
    /// Wave C: Stationarity with memory preservation
    pub enable_fractional_diff: bool,

    /// Enable regime detection features (variable)
    /// Wave C: CUSUM structural breaks, Adaptive strategies
    pub enable_regime_detection: bool,

    /// Enable Wave D regime detection features (24 features)
    /// Wave D: CUSUM statistics (10), ADX directional (5), Regime transitions (5), Adaptive strategies (4)
    pub enable_wave_d_regime: bool,
}

/// Feature engineering phase (Wave 19 progressive implementation)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum FeaturePhase {
    /// Wave A: 26 features (baseline technical indicators + microstructure)
    WaveA,
    /// Wave B: 36 features (adds alternative bars + barrier optimization)
    WaveB,
    /// Wave C: 201 features (adds fractional diff + regime detection)
    WaveC,
    /// Wave D: 225 features (adds Wave D regime detection + adaptive strategies)
    WaveD,
}

impl Default for FeatureConfig {
    /// Default configuration: Wave A (26 features)
    fn default() -> Self {
        Self::wave_a()
    }
}

impl FeatureConfig {
    /// Wave A configuration: 26 features (baseline)
    ///
    /// Feature breakdown:
    /// - OHLCV: 5 features (open, high, low, close, volume)
    /// - Technical indicators: 21 features (RSI, MACD, Bollinger, ATR, ADX, CCI, Stochastic, EMAs, etc.)
    /// - Microstructure: 0 features (not yet integrated into 26-feature system)
    ///
    /// Total: 26 features
    ///
    /// Note: Microstructure features (Amihud, Roll, Corwin-Schultz) exist in ml crate
    /// but are not yet integrated into `common/ml_strategy.rs` 26-feature system.
    pub const fn wave_a() -> Self {
        Self {
            phase: FeaturePhase::WaveA,
            enable_ohlcv: true,
            enable_technical_indicators: true,
            enable_microstructure: false, // Not yet integrated into 26-feature system
            enable_alternative_bars: false,
            enable_barrier_optimization: false,
            enable_fractional_diff: false,
            enable_regime_detection: false,
            enable_wave_d_regime: false,
        }
    }

    /// Wave B configuration: 36 features (alternative bars)
    ///
    /// Feature breakdown:
    /// - Wave A: 26 features (OHLCV + technical indicators)
    /// - Alternative bars: 10 features (dollar, volume, tick, run, imbalance bars)
    ///
    /// Total: 36 features
    pub const fn wave_b() -> Self {
        Self {
            phase: FeaturePhase::WaveB,
            enable_ohlcv: true,
            enable_technical_indicators: true,
            enable_microstructure: false,
            enable_alternative_bars: true,
            enable_barrier_optimization: true, // Triple-barrier labels
            enable_fractional_diff: false,
            enable_regime_detection: false,
            enable_wave_d_regime: false,
        }
    }

    /// Wave C configuration: 201 features (advanced)
    ///
    /// Feature breakdown:
    /// - Base: 39 features (OHLCV 5 + Technical 21 + Microstructure 3 + Alternative bars 10)
    /// - Wave C additions: 162 features (fractional differentiation, regime detection, statistical features)
    ///
    /// Total: 201 features (indices 0-200)
    pub const fn wave_c() -> Self {
        Self {
            phase: FeaturePhase::WaveC,
            enable_ohlcv: true,
            enable_technical_indicators: true,
            enable_microstructure: true,
            enable_alternative_bars: true,
            enable_barrier_optimization: true,
            enable_fractional_diff: true,
            enable_regime_detection: true,
            enable_wave_d_regime: false, // Wave D features disabled for Wave C
        }
    }

    /// Wave D configuration: 225 features (regime detection + adaptive strategies)
    ///
    /// Feature breakdown:
    /// - Wave C: 201 features (indices 0-200)
    /// - Wave D additions: 24 features (indices 201-224)
    ///   - CUSUM Statistics: 10 features (indices 201-210)
    ///   - ADX & Directional Indicators: 5 features (indices 211-215)
    ///   - Regime Transition Probabilities: 5 features (indices 216-220)
    ///   - Adaptive Strategy Metrics: 4 features (indices 221-224)
    ///
    /// Total: 225 features (indices 0-224)
    pub const fn wave_d() -> Self {
        Self {
            phase: FeaturePhase::WaveD,
            enable_ohlcv: true,
            enable_technical_indicators: true,
            enable_microstructure: true,
            enable_alternative_bars: true,
            enable_barrier_optimization: true,
            enable_fractional_diff: true,
            enable_regime_detection: true,
            enable_wave_d_regime: true,
        }
    }

    /// Calculate total feature count based on enabled feature groups
    ///
    /// Returns the total number of features that will be extracted
    /// based on the current configuration.
    pub const fn feature_count(&self) -> usize {
        let mut count = 0;

        if self.enable_ohlcv {
            count += 5; // open, high, low, close, volume
        }

        if self.enable_technical_indicators {
            count += 21; // RSI, MACD (2), Bollinger, ATR, ADX, CCI, Stochastic (2), EMAs (3), EMA crosses (2), Williams %R, ROC, Ultimate Osc, OBV, MFI, VWAP
        }

        if self.enable_microstructure {
            count += 3; // Amihud Illiquidity, Roll Measure, Corwin-Schultz Spread
        }

        if self.enable_alternative_bars {
            count += 10; // Dollar bars, Volume bars, Tick bars, Run bars, Imbalance bars (approx)
        }

        if self.enable_barrier_optimization {
            // Barrier features are labels, not input features
            // They affect training but don't add to input dimension
            // count += 0;
        }

        if self.enable_fractional_diff {
            // Wave C should reach 201 total features
            // Base: OHLCV (5) + Technical (21) + Microstructure (3) + Alternative bars (10) = 39
            // Therefore: 201 - 39 = 162 additional features
            count += 162;
        }

        // Note: Wave C's regime_detection flag is part of fractional_diff feature count
        // to achieve the documented 201 features for Wave C

        if self.enable_wave_d_regime {
            count += 24; // Wave D: CUSUM (10) + ADX (5) + Transitions (5) + Adaptive (4)
        }

        count
    }

    /// Get feature indices for each group
    ///
    /// Returns (`start_idx`, `end_idx`) for each enabled feature group.
    /// This allows data loaders to know which indices correspond to which features.
    pub fn feature_indices(&self) -> FeatureIndices {
        let mut indices = FeatureIndices::default();
        let mut current_idx = 0;

        if self.enable_ohlcv {
            indices.ohlcv = Some((current_idx, current_idx + 5));
            current_idx += 5;
        }

        if self.enable_technical_indicators {
            indices.technical_indicators = Some((current_idx, current_idx + 21));
            current_idx += 21;
        }

        if self.enable_microstructure {
            indices.microstructure = Some((current_idx, current_idx + 3));
            current_idx += 3;
        }

        if self.enable_alternative_bars {
            indices.alternative_bars = Some((current_idx, current_idx + 10));
            current_idx += 10;
        }

        if self.enable_fractional_diff {
            // Wave C adds 162 features to reach 201 total (39 base + 162 = 201)
            indices.fractional_diff = Some((current_idx, current_idx + 162));
            current_idx += 162;
        }

        // Note: regime_detection is included in fractional_diff count for Wave C

        if self.enable_wave_d_regime {
            indices.wave_d_regime = Some((current_idx, current_idx + 24));
            // Note: current_idx is intentionally not updated after this
            // as this is the last feature group
        }

        indices
    }

    /// Check if a specific feature group is enabled
    pub const fn is_enabled(&self, group: FeatureGroup) -> bool {
        match group {
            FeatureGroup::OHLCV => self.enable_ohlcv,
            FeatureGroup::TechnicalIndicators => self.enable_technical_indicators,
            FeatureGroup::Microstructure => self.enable_microstructure,
            FeatureGroup::AlternativeBars => self.enable_alternative_bars,
            FeatureGroup::BarrierOptimization => self.enable_barrier_optimization,
            FeatureGroup::FractionalDiff => self.enable_fractional_diff,
            FeatureGroup::RegimeDetection => self.enable_regime_detection,
            FeatureGroup::WaveDRegime => self.enable_wave_d_regime,
        }
    }

    /// Get Wave D feature definitions (indices 201-224)
    ///
    /// Returns a vector of all 24 Wave D features with their indices,
    /// names, and categories. This is useful for feature extraction
    /// pipelines and model training.
    pub fn get_wave_d_features(&self) -> Vec<Feature> {
        if self.enable_wave_d_regime {
            wave_d_features()
        } else {
            vec![]
        }
    }
}

/// Feature group classification
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FeatureGroup {
    /// OHLCV features (5)
    OHLCV,
    /// Technical indicators (21)
    TechnicalIndicators,
    /// Microstructure features (3)
    Microstructure,
    /// Alternative bar features (10)
    AlternativeBars,
    /// Barrier optimization (labels, not features)
    BarrierOptimization,
    /// Fractional differentiation (20)
    FractionalDiff,
    /// Regime detection (10)
    RegimeDetection,
    /// Wave D regime detection (24)
    WaveDRegime,
}

/// Feature index ranges for each group
///
/// Provides (`start_idx`, `end_idx`) for each feature group to allow
/// data loaders and models to identify which indices correspond to which features.
#[derive(Debug, Clone, Default)]
pub struct FeatureIndices {
    /// OHLCV indices (5 features)
    pub ohlcv: Option<(usize, usize)>,
    /// Technical indicator indices (21 features)
    pub technical_indicators: Option<(usize, usize)>,
    /// Microstructure indices (3 features)
    pub microstructure: Option<(usize, usize)>,
    /// Alternative bar indices (10 features)
    pub alternative_bars: Option<(usize, usize)>,
    /// Fractional differentiation indices (20 features)
    pub fractional_diff: Option<(usize, usize)>,
    /// Regime detection indices (10 features)
    pub regime_detection: Option<(usize, usize)>,
    /// Wave D regime detection indices (24 features, indices 201-224)
    pub wave_d_regime: Option<(usize, usize)>,
}

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

    #[test]
    fn test_wave_a_config() {
        let config = FeatureConfig::wave_a();
        assert_eq!(config.phase, FeaturePhase::WaveA);
        assert!(config.enable_ohlcv);
        assert!(config.enable_technical_indicators);
        assert!(!config.enable_microstructure); // Not yet integrated
        assert!(!config.enable_alternative_bars);
        assert_eq!(config.feature_count(), 26);
    }

    #[test]
    fn test_wave_b_config() {
        let config = FeatureConfig::wave_b();
        assert_eq!(config.phase, FeaturePhase::WaveB);
        assert!(config.enable_alternative_bars);
        assert!(config.enable_barrier_optimization);
        assert_eq!(config.feature_count(), 36);
    }

    #[test]
    fn test_wave_c_config() {
        let config = FeatureConfig::wave_c();
        assert_eq!(config.phase, FeaturePhase::WaveC);
        assert!(config.enable_fractional_diff);
        assert!(config.enable_regime_detection);
        assert!(!config.enable_wave_d_regime);
        assert_eq!(config.feature_count(), 201); // Wave C has exactly 201 features
    }

    #[test]
    fn test_wave_d_config() {
        let config = FeatureConfig::wave_d();
        assert_eq!(config.phase, FeaturePhase::WaveD);
        assert!(config.enable_fractional_diff);
        assert!(config.enable_regime_detection);
        assert!(config.enable_wave_d_regime);
        assert_eq!(config.feature_count(), 225); // Wave D has exactly 225 features
    }

    #[test]
    fn test_wave_d_features() {
        let features = wave_d_features();
        assert_eq!(features.len(), 24);

        // Verify indices are correct (201-224)
        assert_eq!(features[0].index, 201);
        assert_eq!(features[23].index, 224);

        // Verify CUSUM features (10)
        let cusum_features: Vec<_> = features
            .iter()
            .filter(|f| f.index >= 201 && f.index <= 210)
            .collect();
        assert_eq!(cusum_features.len(), 10);

        // Verify ADX features (5)
        let adx_features: Vec<_> = features
            .iter()
            .filter(|f| f.index >= 211 && f.index <= 215)
            .collect();
        assert_eq!(adx_features.len(), 5);

        // Verify transition features (5)
        let transition_features: Vec<_> = features
            .iter()
            .filter(|f| f.index >= 216 && f.index <= 220)
            .collect();
        assert_eq!(transition_features.len(), 5);

        // Verify adaptive features (4)
        let adaptive_features: Vec<_> = features
            .iter()
            .filter(|f| f.index >= 221 && f.index <= 224)
            .collect();
        assert_eq!(adaptive_features.len(), 4);
    }

    #[test]
    fn test_feature_indices_wave_a() {
        let config = FeatureConfig::wave_a();
        let indices = config.feature_indices();

        assert_eq!(indices.ohlcv, Some((0, 5)));
        assert_eq!(indices.technical_indicators, Some((5, 26)));
        assert_eq!(indices.microstructure, None); // Not enabled in Wave A
        assert_eq!(indices.alternative_bars, None);
    }

    #[test]
    fn test_feature_indices_wave_b() {
        let config = FeatureConfig::wave_b();
        let indices = config.feature_indices();

        assert_eq!(indices.ohlcv, Some((0, 5)));
        assert_eq!(indices.technical_indicators, Some((5, 26)));
        assert_eq!(indices.alternative_bars, Some((26, 36)));
    }

    #[test]
    fn test_feature_indices_wave_d() {
        let config = FeatureConfig::wave_d();
        let indices = config.feature_indices();

        // Verify Wave D indices exist and are at the end
        assert!(indices.wave_d_regime.is_some());
        let (start, end) = indices.wave_d_regime.unwrap();
        assert_eq!(end - start, 24); // 24 Wave D features
                                     // Wave D features should start after Wave C features (201+)
        assert!(start >= 201);
    }

    #[test]
    fn test_is_enabled() {
        let config = FeatureConfig::wave_a();
        assert!(config.is_enabled(FeatureGroup::OHLCV));
        assert!(config.is_enabled(FeatureGroup::TechnicalIndicators));
        assert!(!config.is_enabled(FeatureGroup::AlternativeBars));
        assert!(!config.is_enabled(FeatureGroup::WaveDRegime));

        let config = FeatureConfig::wave_d();
        assert!(config.is_enabled(FeatureGroup::WaveDRegime));
    }

    #[test]
    fn test_get_wave_d_features() {
        let config = FeatureConfig::wave_d();
        let features = config.get_wave_d_features();
        assert_eq!(features.len(), 24);

        let config = FeatureConfig::wave_c();
        let features = config.get_wave_d_features();
        assert_eq!(features.len(), 0); // Wave C doesn't have Wave D features enabled
    }

    #[test]
    fn test_default_is_wave_a() {
        let config = FeatureConfig::default();
        assert_eq!(config.phase, FeaturePhase::WaveA);
        assert_eq!(config.feature_count(), 26);
    }
}
