//! FeatureConfig System for Managing Feature Extraction
//!
//! This module provides a flexible configuration system for managing feature extraction
//! across all services (training, inference, backtesting). It supports multiple Wave levels
//! (A, B, C) with progressive feature enhancement.
//!
//! # Architecture
//!
//! ```text
//! FeatureConfig
//!     ├─ Wave Level (A, B, C, D)
//!     ├─ Enabled Features (Vec<FeatureType>)
//!     ├─ Feature Count (dynamic)
//!     └─ Feature Index Mapping (HashMap<FeatureType, Range<usize>>)
//! ```
//!
//! # Wave Progression
//!
//! - **Wave A** (26 features): Base technical indicators + oscillators + volume
//! - **Wave B** (36 features): Wave A + alternative bars (tick, volume, dollar, imbalance, run)
//! - **Wave C** (65+ features): Wave B + price/volume/microstructure/time/statistical features
//! - **Wave D** (future): Wave C + fractional differentiation + meta-labeling + structural breaks
//!
//! # Usage Example
//!
//! ```rust
//! use ml::config::{FeatureConfig, WaveLevel};
//!
//! // Create Wave A configuration (26 features)
//! let config = FeatureConfig::from_wave(WaveLevel::WaveA);
//! assert_eq!(config.feature_count(), 26);
//!
//! // Create Wave B configuration (36 features)
//! let config_b = FeatureConfig::from_wave(WaveLevel::WaveB);
//! assert_eq!(config_b.feature_count(), 36);
//!
//! // Create Wave C configuration (65+ features)
//! let config_c = FeatureConfig::from_wave(WaveLevel::WaveC);
//! assert!(config_c.feature_count() >= 65);
//! ```

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::ops::Range;

/// Wave level for progressive feature enhancement
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum WaveLevel {
    /// Wave A: Base technical indicators (26 features)
    WaveA,
    /// Wave B: Wave A + alternative bars (36 features)
    WaveB,
    /// Wave C: Wave B + comprehensive features (65+ features)
    WaveC,
    /// Wave D: Wave C + fractional diff + meta-labeling (future)
    WaveD,
}

/// Feature type enumeration for all available features
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum FeatureType {
    // ===== Wave A Features (26 total) =====

    // Base Features (7)
    /// Price return (current - prev) / prev
    PriceReturn,
    /// Short-term MA ratio (current / SMA(5) - 1.0)
    ShortMARatio,
    /// Volatility (std_dev of returns, 10-period)
    Volatility,
    /// Volume ratio (current / prev - 1.0)
    VolumeRatio,
    /// Volume MA ratio (current / SMA_vol(5) - 1.0)
    VolumeMARatio,
    /// Hour of day (normalized)
    Hour,
    /// Day of week (normalized)
    DayOfWeek,

    // Oscillators (3)
    /// Williams %R (14-period momentum oscillator)
    WilliamsR,
    /// Rate of Change (12-period momentum)
    ROC,
    /// Ultimate Oscillator (7/14/28 multi-timeframe)
    UltimateOscillator,

    // Volume Indicators (3)
    /// On-Balance Volume (cumulative volume flow)
    OBV,
    /// Money Flow Index (14-period, volume-weighted RSI)
    MFI,
    /// VWAP Ratio (price distance from VWAP)
    VWAPRatio,

    // EMA Features (5)
    /// EMA-9 normalized
    EMA9Norm,
    /// EMA-21 normalized
    EMA21Norm,
    /// EMA-50 normalized
    EMA50Norm,
    /// EMA 9/21 cross signal
    EMA9_21Cross,
    /// EMA 21/50 cross signal
    EMA21_50Cross,

    // Technical Indicators (8)
    /// ADX (Average Directional Index, trend strength)
    ADX,
    /// Bollinger Bands Position (volatility/mean reversion)
    BollingerPosition,
    /// Stochastic %K (14-period momentum oscillator)
    StochasticK,
    /// Stochastic %D (3-period SMA of %K, signal line)
    StochasticD,
    /// CCI (Commodity Channel Index, 20-period momentum)
    CCI,
    /// RSI (Relative Strength Index, 14-period)
    RSI,
    /// MACD Line (EMA(12) - EMA(26))
    MACD,
    /// MACD Signal Line (EMA(9) of MACD)
    MACDSignal,

    // ===== Wave B Features (10 additional, 36 total) =====
    /// Tick bars (count-based sampling)
    TickBars,
    /// Volume bars (volume-based sampling)
    VolumeBars,
    /// Dollar bars (dollar volume-based sampling)
    DollarBars,
    /// Imbalance bars (order flow imbalance)
    ImbalanceBars,
    /// Run bars (directional runs)
    RunBars,
    /// Barrier labels (triple-barrier method)
    BarrierLabels,
    /// Barrier optimization features
    BarrierOptimization,
    /// EWMA thresholds (exponential moving average)
    EWMAThresholds,
    /// Meta-labeling primary model
    MetaLabelingPrimary,
    /// Meta-labeling secondary model
    MetaLabelingSecondary,

    // ===== Wave C Features (29+ additional, 65+ total) =====

    // Price Features (8)
    /// Price patterns and trends
    PricePatterns,
    /// Moving average relationships
    MovingAverages,
    /// High/Low analysis
    HighLowAnalysis,
    /// Trend detection and strength
    TrendDetection,
    /// Support/Resistance levels
    SupportResistance,
    /// Candlestick patterns
    CandlestickPatterns,
    /// Multi-period analysis
    MultiPeriodAnalysis,
    /// Price extremes and percentiles
    PriceExtremes,

    // Volume Features (6)
    /// Volume moving averages
    VolumeMovingAverages,
    /// Volume momentum
    VolumeMomentum,
    /// Up/Down volume ratio
    UpDownVolumeRatio,
    /// Volume percentiles
    VolumePercentiles,
    /// Price-volume correlation
    PriceVolumeCorrelation,
    /// Volume clusters
    VolumeClusters,

    // Microstructure Features (3)
    /// Roll Measure (effective spread estimator)
    RollMeasure,
    /// Amihud Illiquidity (price impact measure)
    AmihudIlliquidity,
    /// Corwin-Schultz Spread (high-low volatility decomposition)
    CorwinSchultzSpread,

    // Time-Based Features (1 category, 10 individual features)
    /// Time-based features (hour, day, market hours, session)
    TimeBasedFeatures,

    // Statistical Features (11 categories)
    /// Rolling statistics (mean, std, percentiles)
    RollingStatistics,
    /// Autocorrelations (lag-1, lag-5, lag-10)
    Autocorrelations,
    /// Skewness (5, 10, 20, 50 periods)
    Skewness,
    /// Kurtosis (5, 10, 20, 50 periods)
    Kurtosis,
    /// Percentiles (10th, 25th, 50th, 75th, 90th)
    Percentiles,
    /// Realized volatility (5, 10, 20 periods)
    RealizedVolatility,
    /// Parkinson volatility (high-low range)
    ParkinsonVolatility,
    /// Garman-Klass volatility (OHLC-based)
    GarmanKlassVolatility,
    /// Cross-correlations (price-volume, range-volume)
    CrossCorrelations,
    /// Volatility regime indicators
    VolatilityRegime,
    /// Trend/Volume regime classification
    TrendVolumeRegime,

    // ===== Wave D Features (future) =====
    /// Fractional differentiation (stationarity with memory)
    FractionalDifferentiation,
    /// Structural breaks (CUSUM detection)
    StructuralBreaks,
    /// Adaptive strategies (regime switching)
    AdaptiveStrategies,
}

impl FeatureType {
    /// Get human-readable name for feature
    pub fn name(&self) -> &str {
        match self {
            // Wave A Base Features
            Self::PriceReturn => "price_return",
            Self::ShortMARatio => "short_ma_ratio",
            Self::Volatility => "volatility",
            Self::VolumeRatio => "volume_ratio",
            Self::VolumeMARatio => "volume_ma_ratio",
            Self::Hour => "hour",
            Self::DayOfWeek => "day_of_week",

            // Wave A Oscillators
            Self::WilliamsR => "williams_r",
            Self::ROC => "roc",
            Self::UltimateOscillator => "ultimate_oscillator",

            // Wave A Volume Indicators
            Self::OBV => "obv",
            Self::MFI => "mfi",
            Self::VWAPRatio => "vwap_ratio",

            // Wave A EMA Features
            Self::EMA9Norm => "ema_9_norm",
            Self::EMA21Norm => "ema_21_norm",
            Self::EMA50Norm => "ema_50_norm",
            Self::EMA9_21Cross => "ema_9_21_cross",
            Self::EMA21_50Cross => "ema_21_50_cross",

            // Wave A Technical Indicators
            Self::ADX => "adx",
            Self::BollingerPosition => "bollinger_position",
            Self::StochasticK => "stochastic_k",
            Self::StochasticD => "stochastic_d",
            Self::CCI => "cci",
            Self::RSI => "rsi",
            Self::MACD => "macd",
            Self::MACDSignal => "macd_signal",

            // Wave B Alternative Bars
            Self::TickBars => "tick_bars",
            Self::VolumeBars => "volume_bars",
            Self::DollarBars => "dollar_bars",
            Self::ImbalanceBars => "imbalance_bars",
            Self::RunBars => "run_bars",
            Self::BarrierLabels => "barrier_labels",
            Self::BarrierOptimization => "barrier_optimization",
            Self::EWMAThresholds => "ewma_thresholds",
            Self::MetaLabelingPrimary => "meta_labeling_primary",
            Self::MetaLabelingSecondary => "meta_labeling_secondary",

            // Wave C Price Features
            Self::PricePatterns => "price_patterns",
            Self::MovingAverages => "moving_averages",
            Self::HighLowAnalysis => "high_low_analysis",
            Self::TrendDetection => "trend_detection",
            Self::SupportResistance => "support_resistance",
            Self::CandlestickPatterns => "candlestick_patterns",
            Self::MultiPeriodAnalysis => "multi_period_analysis",
            Self::PriceExtremes => "price_extremes",

            // Wave C Volume Features
            Self::VolumeMovingAverages => "volume_moving_averages",
            Self::VolumeMomentum => "volume_momentum",
            Self::UpDownVolumeRatio => "up_down_volume_ratio",
            Self::VolumePercentiles => "volume_percentiles",
            Self::PriceVolumeCorrelation => "price_volume_correlation",
            Self::VolumeClusters => "volume_clusters",

            // Wave C Microstructure Features
            Self::RollMeasure => "roll_measure",
            Self::AmihudIlliquidity => "amihud_illiquidity",
            Self::CorwinSchultzSpread => "corwin_schultz_spread",

            // Wave C Time-Based Features
            Self::TimeBasedFeatures => "time_based_features",

            // Wave C Statistical Features
            Self::RollingStatistics => "rolling_statistics",
            Self::Autocorrelations => "autocorrelations",
            Self::Skewness => "skewness",
            Self::Kurtosis => "kurtosis",
            Self::Percentiles => "percentiles",
            Self::RealizedVolatility => "realized_volatility",
            Self::ParkinsonVolatility => "parkinson_volatility",
            Self::GarmanKlassVolatility => "garman_klass_volatility",
            Self::CrossCorrelations => "cross_correlations",
            Self::VolatilityRegime => "volatility_regime",
            Self::TrendVolumeRegime => "trend_volume_regime",

            // Wave D Features (future)
            Self::FractionalDifferentiation => "fractional_differentiation",
            Self::StructuralBreaks => "structural_breaks",
            Self::AdaptiveStrategies => "adaptive_strategies",
        }
    }

    /// Get feature dimensionality (number of individual features produced)
    pub fn dimensionality(&self) -> usize {
        match self {
            // Wave A Base Features (7 individual features)
            Self::PriceReturn => 1,
            Self::ShortMARatio => 1,
            Self::Volatility => 1,
            Self::VolumeRatio => 1,
            Self::VolumeMARatio => 1,
            Self::Hour => 1,
            Self::DayOfWeek => 1,

            // Wave A Oscillators (3 individual features)
            Self::WilliamsR => 1,
            Self::ROC => 1,
            Self::UltimateOscillator => 1,

            // Wave A Volume Indicators (3 individual features)
            Self::OBV => 1,
            Self::MFI => 1,
            Self::VWAPRatio => 1,

            // Wave A EMA Features (5 individual features)
            Self::EMA9Norm => 1,
            Self::EMA21Norm => 1,
            Self::EMA50Norm => 1,
            Self::EMA9_21Cross => 1,
            Self::EMA21_50Cross => 1,

            // Wave A Technical Indicators (8 individual features)
            Self::ADX => 1,
            Self::BollingerPosition => 1,
            Self::StochasticK => 1,
            Self::StochasticD => 1,
            Self::CCI => 1,
            Self::RSI => 1,
            Self::MACD => 1,
            Self::MACDSignal => 1,

            // Wave B Alternative Bars (1 feature each)
            Self::TickBars => 1,
            Self::VolumeBars => 1,
            Self::DollarBars => 1,
            Self::ImbalanceBars => 1,
            Self::RunBars => 1,
            Self::BarrierLabels => 1,
            Self::BarrierOptimization => 1,
            Self::EWMAThresholds => 1,
            Self::MetaLabelingPrimary => 1,
            Self::MetaLabelingSecondary => 1,

            // Wave C Price Features (60 total individual features)
            Self::PricePatterns => 8,       // 8 features
            Self::MovingAverages => 5,      // 5 features
            Self::HighLowAnalysis => 4,     // 4 features
            Self::TrendDetection => 4,      // 4 features
            Self::SupportResistance => 8,   // 8 features
            Self::CandlestickPatterns => 8, // 8 features
            Self::MultiPeriodAnalysis => 8, // 8 features
            Self::PriceExtremes => 6,       // 6 features

            // Wave C Volume Features (40 total individual features)
            Self::VolumeMovingAverages => 4,   // 4 features
            Self::VolumeMomentum => 6,         // 6 features
            Self::UpDownVolumeRatio => 6,      // 6 features
            Self::VolumePercentiles => 4,      // 4 features
            Self::PriceVolumeCorrelation => 6, // 6 features
            Self::VolumeClusters => 4,         // 4 features

            // Wave C Microstructure Features (3 individual features)
            Self::RollMeasure => 1,
            Self::AmihudIlliquidity => 1,
            Self::CorwinSchultzSpread => 1,

            // Wave C Time-Based Features (10 individual features)
            Self::TimeBasedFeatures => 10,

            // Wave C Statistical Features (81 total individual features)
            Self::RollingStatistics => 20, // 20 features (4 periods × 5 stats)
            Self::Autocorrelations => 9,   // 9 features (lags 1, 2, 3, 4, 5, 6, 8, 10, 12)
            Self::Skewness => 4,           // 4 features (5, 10, 20, 50 periods)
            Self::Kurtosis => 4,           // 4 features (5, 10, 20, 50 periods)
            Self::Percentiles => 10,       // 10 features (5 percentiles × 2 periods)
            Self::RealizedVolatility => 3, // 3 features (5, 10, 20 periods)
            Self::ParkinsonVolatility => 2, // 2 features (10, 20 periods)
            Self::GarmanKlassVolatility => 1, // 1 feature (20 periods)
            Self::CrossCorrelations => 6,  // 6 features
            Self::VolatilityRegime => 6,   // 6 features
            Self::TrendVolumeRegime => 6,  // 6 features

            // Wave D Features (future, TBD)
            Self::FractionalDifferentiation => 5, // Estimate: 5 features
            Self::StructuralBreaks => 3,          // Estimate: 3 features
            Self::AdaptiveStrategies => 4,        // Estimate: 4 features
        }
    }
}

/// Feature configuration for ML models
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeatureConfig {
    /// Wave level (determines base feature set)
    pub wave_level: WaveLevel,
    /// Enabled features
    pub enabled_features: Vec<FeatureType>,
}

impl FeatureConfig {
    /// Create configuration for a specific wave level
    pub fn from_wave(wave: WaveLevel) -> Self {
        let enabled_features = match wave {
            WaveLevel::WaveA => Self::wave_a_features(),
            WaveLevel::WaveB => Self::wave_b_features(),
            WaveLevel::WaveC => Self::wave_c_features(),
            WaveLevel::WaveD => Self::wave_d_features(),
        };

        Self {
            wave_level: wave,
            enabled_features,
        }
    }

    /// Get Wave A feature set (26 features)
    fn wave_a_features() -> Vec<FeatureType> {
        vec![
            // Base Features (7)
            FeatureType::PriceReturn,
            FeatureType::ShortMARatio,
            FeatureType::Volatility,
            FeatureType::VolumeRatio,
            FeatureType::VolumeMARatio,
            FeatureType::Hour,
            FeatureType::DayOfWeek,
            // Oscillators (3)
            FeatureType::WilliamsR,
            FeatureType::ROC,
            FeatureType::UltimateOscillator,
            // Volume Indicators (3)
            FeatureType::OBV,
            FeatureType::MFI,
            FeatureType::VWAPRatio,
            // EMA Features (5)
            FeatureType::EMA9Norm,
            FeatureType::EMA21Norm,
            FeatureType::EMA50Norm,
            FeatureType::EMA9_21Cross,
            FeatureType::EMA21_50Cross,
            // Technical Indicators (8)
            FeatureType::ADX,
            FeatureType::BollingerPosition,
            FeatureType::StochasticK,
            FeatureType::StochasticD,
            FeatureType::CCI,
            FeatureType::RSI,
            FeatureType::MACD,
            FeatureType::MACDSignal,
        ]
    }

    /// Get Wave B feature set (36 features = Wave A + 10 alternative bar features)
    fn wave_b_features() -> Vec<FeatureType> {
        let mut features = Self::wave_a_features();

        // Add Wave B features (10 alternative bar features)
        features.extend_from_slice(&[
            FeatureType::TickBars,
            FeatureType::VolumeBars,
            FeatureType::DollarBars,
            FeatureType::ImbalanceBars,
            FeatureType::RunBars,
            FeatureType::BarrierLabels,
            FeatureType::BarrierOptimization,
            FeatureType::EWMAThresholds,
            FeatureType::MetaLabelingPrimary,
            FeatureType::MetaLabelingSecondary,
        ]);

        features
    }

    /// Get Wave C feature set (256 features = Wave B + comprehensive feature engineering)
    fn wave_c_features() -> Vec<FeatureType> {
        let mut features = Self::wave_b_features();

        // Add Wave C Price Features (60 features)
        features.extend_from_slice(&[
            FeatureType::PricePatterns,
            FeatureType::MovingAverages,
            FeatureType::HighLowAnalysis,
            FeatureType::TrendDetection,
            FeatureType::SupportResistance,
            FeatureType::CandlestickPatterns,
            FeatureType::MultiPeriodAnalysis,
            FeatureType::PriceExtremes,
        ]);

        // Add Wave C Volume Features (40 features)
        features.extend_from_slice(&[
            FeatureType::VolumeMovingAverages,
            FeatureType::VolumeMomentum,
            FeatureType::UpDownVolumeRatio,
            FeatureType::VolumePercentiles,
            FeatureType::PriceVolumeCorrelation,
            FeatureType::VolumeClusters,
        ]);

        // Add Wave C Microstructure Features (3 features)
        features.extend_from_slice(&[
            FeatureType::RollMeasure,
            FeatureType::AmihudIlliquidity,
            FeatureType::CorwinSchultzSpread,
        ]);

        // Add Wave C Time-Based Features (10 features)
        features.push(FeatureType::TimeBasedFeatures);

        // Add Wave C Statistical Features (81 features)
        features.extend_from_slice(&[
            FeatureType::RollingStatistics,
            FeatureType::Autocorrelations,
            FeatureType::Skewness,
            FeatureType::Kurtosis,
            FeatureType::Percentiles,
            FeatureType::RealizedVolatility,
            FeatureType::ParkinsonVolatility,
            FeatureType::GarmanKlassVolatility,
            FeatureType::CrossCorrelations,
            FeatureType::VolatilityRegime,
            FeatureType::TrendVolumeRegime,
        ]);

        features
    }

    /// Get Wave D feature set (future: fractional diff + meta-labeling + structural breaks)
    fn wave_d_features() -> Vec<FeatureType> {
        let mut features = Self::wave_c_features();

        // Add Wave D features (future)
        features.extend_from_slice(&[
            FeatureType::FractionalDifferentiation,
            FeatureType::StructuralBreaks,
            FeatureType::AdaptiveStrategies,
        ]);

        features
    }

    /// Get total feature count
    pub fn feature_count(&self) -> usize {
        self.enabled_features
            .iter()
            .map(|ft| ft.dimensionality())
            .sum()
    }

    /// Get feature index mapping
    ///
    /// Returns a HashMap mapping each FeatureType to its index range in the feature vector.
    /// This is critical for:
    /// - Training: Knowing which indices correspond to which features
    /// - Inference: Extracting the right feature slices
    /// - Debugging: Understanding feature vector layout
    pub fn feature_indices(&self) -> HashMap<FeatureType, Range<usize>> {
        let mut indices = HashMap::new();
        let mut current_idx = 0;

        for feature_type in &self.enabled_features {
            let dim = feature_type.dimensionality();
            indices.insert(*feature_type, current_idx..(current_idx + dim));
            current_idx += dim;
        }

        indices
    }

    /// Get human-readable feature names in order
    pub fn get_feature_names(&self) -> Vec<String> {
        let mut names = Vec::new();

        for feature_type in &self.enabled_features {
            let base_name = feature_type.name();
            let dim = feature_type.dimensionality();

            if dim == 1 {
                names.push(base_name.to_string());
            } else {
                // For multi-dimensional features, append indices
                for i in 0..dim {
                    names.push(format!("{}_{}", base_name, i));
                }
            }
        }

        names
    }

    /// Validate feature vector matches configuration
    pub fn validate_feature_vector(&self, features: &[f64]) -> Result<(), String> {
        let expected_count = self.feature_count();
        if features.len() != expected_count {
            return Err(format!(
                "Feature vector length mismatch: expected {}, got {}",
                expected_count,
                features.len()
            ));
        }

        // Validate no NaN/Inf
        for (i, &val) in features.iter().enumerate() {
            if !val.is_finite() {
                return Err(format!("Invalid feature at index {}: {}", i, val));
            }
        }

        Ok(())
    }
}

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

    #[test]
    fn test_wave_a_config() {
        let config = FeatureConfig::from_wave(WaveLevel::WaveA);
        assert_eq!(config.feature_count(), 26);
        assert_eq!(config.enabled_features.len(), 26);
    }

    #[test]
    fn test_wave_b_config() {
        let config = FeatureConfig::from_wave(WaveLevel::WaveB);
        assert_eq!(config.feature_count(), 36);
        assert_eq!(config.enabled_features.len(), 36);
    }

    #[test]
    fn test_wave_c_config() {
        let config = FeatureConfig::from_wave(WaveLevel::WaveC);

        // Wave C breakdown (actual dimensionality values):
        // Wave A: 26 features
        // Wave B: +10 features = 36 total
        // Wave C additions:
        //   - Price Features: 51 (8+5+4+4+8+8+8+6)
        //   - Volume Features: 30 (4+6+6+4+6+4)
        //   - Microstructure Features: 3 (Roll, Amihud, Corwin-Schultz)
        //   - Time-Based Features: 10
        //   - Statistical Features: 71 (20+9+4+4+10+3+2+1+6+6+6)
        // Total: 36 + 165 = 201 features

        assert_eq!(config.feature_count(), 201);
        assert!(config.feature_count() >= 65);
    }

    #[test]
    fn test_wave_d_config() {
        let config = FeatureConfig::from_wave(WaveLevel::WaveD);
        // Wave D adds fractional diff (5) + structural breaks (3) + adaptive strategies (4) = 12
        // Total: 201 (Wave C) + 12 (Wave D) = 213 features
        assert!(config.feature_count() >= 210);
        assert_eq!(config.feature_count(), 213);
    }

    #[test]
    fn test_feature_indices_non_overlapping() {
        let config = FeatureConfig::from_wave(WaveLevel::WaveA);
        let indices = config.feature_indices();

        // Verify no overlapping ranges
        let mut all_indices: Vec<usize> = Vec::new();
        for range in indices.values() {
            for i in range.clone() {
                assert!(
                    !all_indices.contains(&i),
                    "Index {} appears in multiple feature ranges",
                    i
                );
                all_indices.push(i);
            }
        }

        // Verify all indices from 0 to feature_count-1 are covered
        all_indices.sort();
        assert_eq!(all_indices.len(), config.feature_count());
        assert_eq!(all_indices[0], 0);
        assert_eq!(
            all_indices[all_indices.len() - 1],
            config.feature_count() - 1
        );
    }

    #[test]
    fn test_feature_names() {
        let config = FeatureConfig::from_wave(WaveLevel::WaveA);
        let names = config.get_feature_names();

        assert_eq!(names.len(), 26);
        assert_eq!(names[0], "price_return");
        assert_eq!(names[18], "adx");
        assert_eq!(names[23], "rsi");
        assert_eq!(names[24], "macd");
        assert_eq!(names[25], "macd_signal");
    }

    #[test]
    fn test_validate_feature_vector() {
        let config = FeatureConfig::from_wave(WaveLevel::WaveA);

        // Valid vector
        let valid_features = vec![0.5; 26];
        assert!(config.validate_feature_vector(&valid_features).is_ok());

        // Invalid length
        let invalid_length = vec![0.5; 20];
        assert!(config.validate_feature_vector(&invalid_length).is_err());

        // Contains NaN
        let mut invalid_nan = vec![0.5; 26];
        invalid_nan[10] = f64::NAN;
        assert!(config.validate_feature_vector(&invalid_nan).is_err());

        // Contains Inf
        let mut invalid_inf = vec![0.5; 26];
        invalid_inf[15] = f64::INFINITY;
        assert!(config.validate_feature_vector(&invalid_inf).is_err());
    }

    #[test]
    fn test_feature_dimensionality() {
        // Test individual feature dimensions
        assert_eq!(FeatureType::PriceReturn.dimensionality(), 1);
        assert_eq!(FeatureType::RSI.dimensionality(), 1);
        assert_eq!(FeatureType::PricePatterns.dimensionality(), 8);
        assert_eq!(FeatureType::VolumeMovingAverages.dimensionality(), 4);
        assert_eq!(FeatureType::TimeBasedFeatures.dimensionality(), 10);
        assert_eq!(FeatureType::RollingStatistics.dimensionality(), 20);
    }

    #[test]
    fn test_serialization() {
        let config = FeatureConfig::from_wave(WaveLevel::WaveB);

        // Serialize to JSON
        let json = serde_json::to_string(&config).unwrap();
        assert!(json.contains("WaveB"));

        // Deserialize from JSON
        let deserialized: FeatureConfig = serde_json::from_str(&json).unwrap();
        assert_eq!(deserialized.feature_count(), config.feature_count());
        assert_eq!(deserialized.wave_level, config.wave_level);
    }

    #[test]
    fn test_wave_progression() {
        // Verify that each wave builds upon the previous
        let wave_a = FeatureConfig::from_wave(WaveLevel::WaveA);
        let wave_b = FeatureConfig::from_wave(WaveLevel::WaveB);
        let wave_c = FeatureConfig::from_wave(WaveLevel::WaveC);
        let wave_d = FeatureConfig::from_wave(WaveLevel::WaveD);

        // Each wave should have more features than the previous
        assert!(wave_b.feature_count() > wave_a.feature_count());
        assert!(wave_c.feature_count() > wave_b.feature_count());
        assert!(wave_d.feature_count() > wave_c.feature_count());

        // Wave B should contain all Wave A features
        for feature in &wave_a.enabled_features {
            assert!(
                wave_b.enabled_features.contains(feature),
                "Wave B missing Wave A feature: {:?}",
                feature
            );
        }

        // Wave C should contain all Wave B features
        for feature in &wave_b.enabled_features {
            assert!(
                wave_c.enabled_features.contains(feature),
                "Wave C missing Wave B feature: {:?}",
                feature
            );
        }
    }
}
