use std::env;

use crate::trend_value::TrendValue;
use lazy_static::lazy_static;

lazy_static! {
    static ref TREND_THRESHOLD: f64 = env::var("TREND_THRESHOLD")
        .unwrap_or_else(|_| "0.005".to_string())
        .parse()
        .unwrap_or(0.005);
}

#[derive(Debug, Clone)]
pub struct TrendMetrics {
    pub short_term_val: TrendValue,
    pub long_term_val: TrendValue,
    pub current_value: Option<f64>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum TrendType {
    StrongUp,
    WeakUp,
    StrongDown,
    WeakDown,
    NoTrend,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CrossOverType {
    GoldenCross,
    DeadCross,
    None,
}

impl TrendMetrics {
    pub fn new(short_period: usize, long_period: usize) -> Self {
        Self {
            short_term_val: TrendValue::new(short_period, short_period * 2),
            long_term_val: TrendValue::new(long_period, long_period * 2),
            current_value: None,
        }
    }

    pub fn update(&mut self, new_value: f64, short_value: f64, long_value: f64) {
        self.current_value = Some(new_value);
        self.short_term_val.update_value(short_value);
        self.long_term_val.update_value(long_value);
    }

    pub fn ema_difference_rate(&self) -> Option<f64> {
        let short_term_ema = self.short_term_val.current_ema();
        let long_term_ema = self.long_term_val.current_ema();
        let ema_difference = (short_term_ema - long_term_ema).abs();

        if long_term_ema != 0.0 {
            Some(ema_difference / long_term_ema.abs())
        } else {
            return None;
        }
    }

    pub fn trend_type_with_angle(&self) -> TrendType {
        let short_term_change_rate = self.short_term_val.ema_change_rate();
        let long_term_change_rate = self.long_term_val.ema_change_rate();

        let trend_threshod = *TREND_THRESHOLD / 2.0;

        if short_term_change_rate > long_term_change_rate && short_term_change_rate > trend_threshod
        {
            return TrendType::WeakUp;
        }

        if short_term_change_rate < long_term_change_rate
            && short_term_change_rate < -trend_threshod
        {
            return TrendType::WeakDown;
        }

        self.trend_type()
    }

    fn trend_type(&self) -> TrendType {
        match self.ema_difference_rate() {
            Some(relative_difference) => {
                if relative_difference < *TREND_THRESHOLD {
                    return TrendType::NoTrend;
                }
            }
            None => {
                return TrendType::NoTrend;
            }
        }

        let short_term_ema = self.short_term_val.current_ema();
        let long_term_ema = self.long_term_val.current_ema();

        match (
            short_term_ema > long_term_ema,
            self.current_value.unwrap_or_default() > short_term_ema,
        ) {
            (true, true) => TrendType::StrongUp,
            (true, false) => TrendType::WeakUp,
            (false, false) => TrendType::StrongDown,
            (false, true) => TrendType::WeakDown,
        }
    }

    #[allow(dead_code)]
    pub fn is_trend_up(&self) -> bool {
        match self.trend_type() {
            TrendType::StrongUp | TrendType::WeakUp => true,
            TrendType::StrongDown | TrendType::WeakDown => false,
            TrendType::NoTrend => false,
        }
    }

    pub fn is_trend_weak(&self) -> bool {
        match self.trend_type() {
            TrendType::WeakUp | TrendType::WeakDown => true,
            TrendType::StrongUp | TrendType::StrongDown => false,
            TrendType::NoTrend => false,
        }
    }

    pub fn is_crossover(&self) -> CrossOverType {
        // Short term crosses above long term
        if self.short_term_val.current_ema() > self.long_term_val.current_ema()
            && self.short_term_val.previous_ema() <= self.long_term_val.previous_ema()
        {
            return CrossOverType::GoldenCross;
        }

        // Short term crosses below long term
        if self.short_term_val.current_ema() < self.long_term_val.current_ema()
            && self.short_term_val.previous_ema() >= self.long_term_val.previous_ema()
        {
            return CrossOverType::DeadCross;
        }

        CrossOverType::None
    }
}
