//! Technical indicators for trading signals.
//!
//! This module provides a comprehensive set of technical indicators
//! commonly used in quantitative finance and algorithmic trading.

pub mod moving_averages;
pub mod momentum;
pub mod volatility;
pub mod volume;
pub mod trend;

pub use moving_averages::*;
pub use momentum::*;
pub use volatility::*;
pub use volume::*;
pub use trend::*;

use crate::config::{StrategyConfig, StrategyKind};

/// Signal generated by an indicator.
#[derive(Default, Clone, Copy, Debug)]
pub struct Signal {
    pub long: bool,
    pub short: bool,
}

/// Bar data for indicator calculations.
#[derive(Clone, Copy, Debug)]
pub struct BarInput {
    pub open: f64,
    pub high: f64,
    pub low: f64,
    pub close: f64,
    pub volume: f64,
}

/// Unified indicator state that wraps all indicator types.
pub enum IndicatorState {
    Ma(MaCrossState),
    Rsi(RsiState),
    Bollinger(BollingerState),
    Macd(MacdState),
    Stochastic(StochasticState),
    Adx(AdxState),
    Atr(AtrState),
    Cci(CciState),
    Obv(ObvState),
    Vwap(VwapState),
    Keltner(KeltnerState),
    Donchian(DonchianState),
    Ichimoku(IchimokuState),
    SuperTrend(SuperTrendState),
    Williams(WilliamsState),
    Aroon(AroonState),
    Mfi(MfiState),
    Roc(RocState),
    Tsi(TsiState),
    UltimateOscillator(UltimateOscillatorState),
    External,
}

impl IndicatorState {
    /// Create a new indicator state based on strategy kind and config.
    pub fn new(strategy: StrategyKind, cfg: &StrategyConfig) -> Self {
        match strategy {
            StrategyKind::MaCross => {
                IndicatorState::Ma(MaCrossState::new(cfg.fast_window, cfg.slow_window, &cfg.ma_type))
            }
            StrategyKind::Rsi => {
                IndicatorState::Rsi(RsiState::new(cfg.rsi_period, cfg.rsi_lower, cfg.rsi_upper))
            }
            StrategyKind::Bollinger => {
                IndicatorState::Bollinger(BollingerState::new(cfg.bollinger_period, cfg.bollinger_std))
            }
            StrategyKind::Macd => {
                IndicatorState::Macd(MacdState::new(cfg.macd_fast, cfg.macd_slow, cfg.macd_signal))
            }
            StrategyKind::Stochastic => {
                IndicatorState::Stochastic(StochasticState::new(
                    cfg.stoch_k_period,
                    cfg.stoch_d_period,
                    cfg.stoch_lower,
                    cfg.stoch_upper,
                ))
            }
            StrategyKind::Adx => {
                IndicatorState::Adx(AdxState::new(cfg.adx_period, cfg.adx_threshold))
            }
            StrategyKind::Atr => {
                IndicatorState::Atr(AtrState::new(cfg.atr_period, cfg.atr_multiplier))
            }
            StrategyKind::Cci => {
                IndicatorState::Cci(CciState::new(cfg.cci_period, cfg.cci_lower, cfg.cci_upper))
            }
            StrategyKind::Obv => {
                IndicatorState::Obv(ObvState::new(cfg.obv_ma_period))
            }
            StrategyKind::Vwap => {
                IndicatorState::Vwap(VwapState::new(cfg.vwap_std_mult))
            }
            StrategyKind::Keltner => {
                IndicatorState::Keltner(KeltnerState::new(cfg.keltner_period, cfg.keltner_atr_mult))
            }
            StrategyKind::Donchian => {
                IndicatorState::Donchian(DonchianState::new(cfg.donchian_period))
            }
            StrategyKind::Ichimoku => {
                IndicatorState::Ichimoku(IchimokuState::new(
                    cfg.ichimoku_tenkan,
                    cfg.ichimoku_kijun,
                    cfg.ichimoku_senkou_b,
                ))
            }
            StrategyKind::SuperTrend => {
                IndicatorState::SuperTrend(SuperTrendState::new(
                    cfg.supertrend_period,
                    cfg.supertrend_mult,
                ))
            }
            StrategyKind::Williams => {
                IndicatorState::Williams(WilliamsState::new(
                    cfg.williams_period,
                    cfg.williams_lower,
                    cfg.williams_upper,
                ))
            }
            StrategyKind::Aroon => {
                IndicatorState::Aroon(AroonState::new(cfg.aroon_period, cfg.aroon_threshold))
            }
            StrategyKind::Mfi => {
                IndicatorState::Mfi(MfiState::new(cfg.mfi_period, cfg.mfi_lower, cfg.mfi_upper))
            }
            StrategyKind::Roc => {
                IndicatorState::Roc(RocState::new(cfg.roc_period, cfg.roc_threshold))
            }
            StrategyKind::Tsi => {
                IndicatorState::Tsi(TsiState::new(
                    cfg.tsi_long_period,
                    cfg.tsi_short_period,
                    cfg.tsi_signal_period,
                ))
            }
            StrategyKind::UltimateOscillator => {
                IndicatorState::UltimateOscillator(UltimateOscillatorState::new(
                    cfg.uo_period1,
                    cfg.uo_period2,
                    cfg.uo_period3,
                    cfg.uo_lower,
                    cfg.uo_upper,
                ))
            }
            StrategyKind::External => IndicatorState::External,
        }
    }

    /// Update indicator with new bar data and return signal.
    pub fn update(&mut self, bar: BarInput) -> Signal {
        match self {
            IndicatorState::Ma(state) => state.update(bar.close),
            IndicatorState::Rsi(state) => state.update(bar.close),
            IndicatorState::Bollinger(state) => state.update(bar.close),
            IndicatorState::Macd(state) => state.update(bar.close),
            IndicatorState::Stochastic(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::Adx(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::Atr(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::Cci(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::Obv(state) => state.update(bar.close, bar.volume),
            IndicatorState::Vwap(state) => state.update(bar.high, bar.low, bar.close, bar.volume),
            IndicatorState::Keltner(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::Donchian(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::Ichimoku(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::SuperTrend(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::Williams(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::Aroon(state) => state.update(bar.high, bar.low),
            IndicatorState::Mfi(state) => state.update(bar.high, bar.low, bar.close, bar.volume),
            IndicatorState::Roc(state) => state.update(bar.close),
            IndicatorState::Tsi(state) => state.update(bar.close),
            IndicatorState::UltimateOscillator(state) => state.update(bar.high, bar.low, bar.close),
            IndicatorState::External => Signal::default(),
        }
    }

    /// Get current ATR value if available (for ATR-based stops).
    pub fn get_atr(&self) -> Option<f64> {
        match self {
            IndicatorState::Atr(state) => state.current_atr(),
            IndicatorState::Keltner(state) => state.current_atr(),
            IndicatorState::SuperTrend(state) => state.current_atr(),
            IndicatorState::Adx(state) => state.current_atr(),
            _ => None,
        }
    }
}
