#![allow(unused)]
#![allow(warnings)]

use crate::database_control::*;
use crate::strategy_team::FilteredDataValue;
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
use crate::value_estimation_team::indicators::rsi::{rsi, RsiData};
use futures::{future::try_join_all, lock::Mutex};
use serde::Deserialize;
use sqlx::FromRow;
use std::collections::{HashMap, HashSet};
use std::f64::NAN;
use std::sync::Arc;
use tokio::{fs::*, io::AsyncWriteExt, time::*};

#[derive(Clone, Debug)]
pub struct StochRsiData {
    pub k: f64,
    pub d: f64,
    pub close_time: i64,
}
impl StochRsiData {
    fn new() -> StochRsiData {
        let a = StochRsiData {
            k: 0.0,
            d: 0.0,
            close_time: 0,
        };
        a
    }
}

#[derive(Clone, Debug)]
pub struct StochRsiKData {
    pub stoch_rsi_k_value: f64,
    pub close_time: i64,
}
impl StochRsiKData {
    fn new() -> StochRsiKData {
        let a = StochRsiKData {
            stoch_rsi_k_value: 0.0,
            close_time: 0,
        };
        a
    }
}

// Binance Stoch RSI
pub async fn stoch_rsi(
    rsi_length: usize,
    stoch_rsi_length: usize,
    smooth_k: usize,
    smooth_d: usize,
    input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
    filtered_symbols: &HashMap<String, FilteredDataValue>,
) -> Result<HashMap<String, Vec<StochRsiData>>, Box<dyn std::error::Error + Send + Sync>> {
    let mut stoch_rsi_data_wrapper: HashMap<String, Vec<StochRsiData>> = HashMap::new();
    let mut stoch_rsi_data_wrapper_arc = Arc::new(Mutex::new(stoch_rsi_data_wrapper));

    let rsi_data_map = rsi(rsi_length, input_rt_data, filtered_symbols).await?;
    let mut task_vec = Vec::new();
    for (symbol, rsi_vec) in rsi_data_map {
        let mut stoch_rsi_data = StochRsiData::new();
        let mut stoch_rsi_k_data = StochRsiKData::new();
        let stoch_rsi_data_wrapper_arc_c = Arc::clone(&stoch_rsi_data_wrapper_arc);

        let symbol_c = symbol.clone();
        task_vec.push(tokio::spawn(async move {
            let mut stoch_rsi_data_vec: Vec<StochRsiData> = Vec::new();
            let mut stoch_rsi_k_data_vec: Vec<StochRsiKData> = Vec::new();
            let mut stoch_rsi_vec: Vec<RsiData> = Vec::new();
            let mut stoch_rsi = RsiData::new();

            if rsi_vec.len() >= stoch_rsi_length
                && rsi_vec.len() >= smooth_k
                && rsi_vec.len() >= smooth_d
            {
                let window_iter = rsi_vec.windows(stoch_rsi_length);

                for buffer_window in window_iter {
                    let max_value = buffer_window
                        .iter()
                        .max_by(|x, y| x.rsi_value.partial_cmp(&y.rsi_value).unwrap())
                        .unwrap()
                        .rsi_value;
                    let min_value = buffer_window
                        .iter()
                        .min_by(|x, y| x.rsi_value.partial_cmp(&y.rsi_value).unwrap())
                        .unwrap()
                        .rsi_value;

                    let stoch_rsi_value = if max_value == min_value {
                        max_value
                    } else {
                        (buffer_window.last().unwrap().rsi_value - min_value)
                            / (max_value - min_value)
                    };

                    stoch_rsi.rsi_value = stoch_rsi_value;
                    stoch_rsi.close_time = buffer_window.last().unwrap().close_time;
                    stoch_rsi_vec.push(stoch_rsi.clone());
                }

                // making Stoch RSI K data
                let window_iter = stoch_rsi_vec.windows(smooth_k);
                for buffer_window in window_iter {
                    stoch_rsi_k_data.stoch_rsi_k_value =
                        (buffer_window.iter().fold(0.0, |acc, x| acc + x.rsi_value)
                            / (smooth_k as f64))
                            * 100.0;
                    stoch_rsi_k_data.close_time = buffer_window.last().unwrap().close_time;
                    stoch_rsi_k_data_vec.push(stoch_rsi_k_data.clone());
                }

                // making Stoch RSI D data and Stoch RSI data
                let window_iter = stoch_rsi_k_data_vec.windows(smooth_d);
                for buffer_window in window_iter {
                    stoch_rsi_data.close_time = buffer_window.last().unwrap().close_time;
                    stoch_rsi_data.k = buffer_window.last().unwrap().stoch_rsi_k_value;
                    stoch_rsi_data.d = (buffer_window
                        .iter()
                        .fold(0.0, |acc, x| acc + x.stoch_rsi_k_value)
                        / (smooth_k as f64));
                    stoch_rsi_data_vec.push(stoch_rsi_data.clone());
                }
                let mut stoch_rsi_data_wrapper_lock = stoch_rsi_data_wrapper_arc_c.lock().await;
                stoch_rsi_data_wrapper_lock.insert(symbol_c, stoch_rsi_data_vec.clone());
            }
        }));
    }
    try_join_all(task_vec).await?;
    let a = stoch_rsi_data_wrapper_arc.lock().await.to_owned();
    Ok(a)
}
