use std::{
    env,
    time::{Duration, SystemTime},
};

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.003".to_string())    // 0.3%
        .parse()
        .unwrap_or(0.003);

    static ref CROSS_EFFECTIVE_DURATION_SECS: u64 = env::var("CROSS_EFFECTIVE_DURATION_SECS")
        .unwrap_or_else(|_| "300".to_string()) // 300sec
        .parse()
        .unwrap_or(60);
}

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

#[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),
            long_term_val: TrendValue::new(long_period),
            current_value: None,
            last_crossover_time: None,
            last_crossover_state: CrossOverType::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 short_term_ema = self.short_term_val.current_ema();
        let long_term_ema = self.long_term_val.current_ema();
        let ema_difference_rate = self.ema_difference_rate();
        let current_price = self.current_value.unwrap_or_default();

        if let Some(rate) = ema_difference_rate {
            if rate > *TREND_THRESHOLD {
                let trend_type = match (
                    short_term_ema > long_term_ema,
                    current_price > short_term_ema,
                ) {
                    (true, true) => TrendType::StrongUp,
                    (true, false) => TrendType::WeakUp,
                    (false, true) => TrendType::WeakDown,
                    (false, false) => TrendType::StrongDown,
                };
                return trend_type;
            }
        }

        if (short_term_change_rate - long_term_change_rate).abs() / long_term_change_rate
            > *TREND_THRESHOLD
        {
            if short_term_change_rate > 0.0 {
                return TrendType::WeakUp;
            } else {
                return TrendType::WeakDown;
            }
        }

        TrendType::NoTrend
    }

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

    pub fn is_crossover(&mut self) -> CrossOverType {
        let now = SystemTime::now();
        let crossover_duration = Duration::from_secs(*CROSS_EFFECTIVE_DURATION_SECS);

        let current_state = 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()
        {
            CrossOverType::GoldenCross
        } else 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()
        {
            CrossOverType::DeadCross
        } else {
            CrossOverType::None
        };

        if current_state == CrossOverType::None {
            if let Some(last_crossover_time) = self.last_crossover_time {
                if now.duration_since(last_crossover_time).unwrap_or_default() < crossover_duration
                {
                    return self.last_crossover_state.clone();
                }
            }
            return CrossOverType::None;
        }

        self.last_crossover_time = Some(now);
        self.last_crossover_state = current_state.clone();

        current_state
    }
}
