use crate::trend_value::TrendValue;
use rust_decimal::Decimal;

#[derive(Debug, Clone)]
pub struct TrendMetrics {
    pub short_term_val: TrendValue,
    pub long_term_val: TrendValue,
    pub macd: TrendValue,
    pub val: TrendValue,
    pub max_val: Decimal,
    pub min_val: Decimal,
    num_std_dev_1: f64,
    num_std_dev_2: f64,
}

impl TrendMetrics {
    pub fn new(name: &str, short_period: usize, long_period: usize, trading_period: usize) -> Self {
        Self {
            short_term_val: TrendValue::new(&(name.to_owned() + "-short"), short_period),
            long_term_val: TrendValue::new(&(name.to_owned() + "-long"), long_period),
            val: TrendValue::new(&(name.to_owned() + "-trading"), trading_period),
            macd: TrendValue::new(&(name.to_owned() + "-trading"), trading_period),
            max_val: Decimal::ZERO,
            min_val: Decimal::MAX,
            num_std_dev_1: 1.0,
            num_std_dev_2: 2.0,
        }
    }

    pub fn update(&mut self, new_value: Decimal, short_value: Decimal, long_value: Decimal) {
        self.short_term_val.update_value(short_value);
        self.long_term_val.update_value(long_value);
        self.val.update_value(new_value);

        self.max_val = std::cmp::max(self.max_val, new_value);
        self.min_val = std::cmp::min(self.min_val, new_value);

        if self.short_term_val.current_ema().is_none() || self.long_term_val.current_ema().is_none()
        {
            return;
        }

        let ema_diff =
            self.short_term_val.current_ema().unwrap() - self.long_term_val.current_ema().unwrap();
        self.macd.update_value(ema_diff);
    }

    pub fn get(&self) -> Option<(Decimal, Decimal, Decimal, Decimal, Decimal, Decimal)> {
        if self.val.current_ema().is_none()
            || self.short_term_val.current_ema().is_none()
            || self.long_term_val.current_ema().is_none()
            || self.macd.current_ema().is_none()
        {
            return None;
        }

        let bolinger_band_positions = self
            .val
            .bollinger_band_positions(&[self.num_std_dev_1, self.num_std_dev_2]);

        let (position_1, position_2) = if bolinger_band_positions.len() == 2 {
            (
                bolinger_band_positions[0]
                    .as_ref()
                    .map_or(Decimal::ZERO, |p| p.to_numeric()),
                bolinger_band_positions[1]
                    .as_ref()
                    .map_or(Decimal::ZERO, |p| p.to_numeric()),
            )
        } else {
            (Decimal::ZERO, Decimal::ZERO)
        };

        Some((
            self.val.current_ema().unwrap(),
            self.short_term_val.current_ema().unwrap(),
            self.long_term_val.current_ema().unwrap(),
            self.macd.current_ema().unwrap(),
            position_1,
            position_2,
        ))
    }
}
