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

use super::HashMap;
use crate::database_control::*;
use crate::strategy_team::FilteredDataValue;
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
use futures::future::try_join_all;
use serde::Deserialize;
use sqlx::FromRow;
use std::sync::Arc;
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};

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

// Binance MA (closeprice)
pub async fn sma(
    moving_number: usize,
    input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
    filtered_symbols: &HashMap<String, FilteredDataValue>,
) -> Result<HashMap<String, Vec<SmaData>>, Box<dyn std::error::Error + Send + Sync>> {
    if filtered_symbols.is_empty() {
        Err("Err")?;
    }

    let mut sma_data_wrapper: HashMap<String, Vec<SmaData>> = HashMap::new();
    let mut sma_data_wrapper_arc = Arc::new(Mutex::new(sma_data_wrapper));

    let mut task_vec = Vec::new();
    for (symbol, filtered_data) in filtered_symbols {
        if let Some(vec) = input_rt_data.get(symbol) {
            let sma_data_wrapper_arc_c = Arc::clone(&sma_data_wrapper_arc);
            let symbol_c = symbol.clone();
            let rt_price_data = vec.clone();
            task_vec.push(tokio::spawn(async move {
                let mut sma_data = SmaData::new();
                let mut sma_data_vec: Vec<SmaData> = Vec::new();

                if rt_price_data.len() >= moving_number {
                    let mut iter = rt_price_data.windows(moving_number);
                    for buffer in iter {
                        let mut avg = 0.0;
                        for element in buffer {
                            avg += element.close_price;
                        }
                        avg /= (moving_number as f64);

                        sma_data.sma_value = avg;
                        sma_data.close_time = buffer.last().unwrap().close_time;
                        sma_data_vec.push(sma_data.clone());
                    }
                }
                let mut sma_data_wrapper_lock = sma_data_wrapper_arc_c.lock().await;
                sma_data_wrapper_lock.insert(symbol_c, sma_data_vec.clone());
            }));
        }
    }
    try_join_all(task_vec).await?;
    let a = sma_data_wrapper_arc.lock().await.to_owned();
    Ok(a)
}

// Binance MA ((open+close)/2)
pub async fn sma_opclo(
    moving_number: usize,
    input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
    filtered_symbols: &HashMap<String, FilteredDataValue>,
) -> Result<HashMap<String, Vec<SmaData>>, Box<dyn std::error::Error + Send + Sync>> {
    if filtered_symbols.is_empty() {
        Err("Err")?;
    }

    let mut sma_data_wrapper: HashMap<String, Vec<SmaData>> = HashMap::new();
    let mut sma_data_wrapper_arc = Arc::new(Mutex::new(sma_data_wrapper));

    let mut task_vec = Vec::new();
    for (symbol, filtered_data) in filtered_symbols {
        if let Some(vec) = input_rt_data.get(symbol) {
            let sma_data_wrapper_arc_c = Arc::clone(&sma_data_wrapper_arc);
            let symbol_c = symbol.clone();
            let rt_price_data = vec.clone();
            task_vec.push(tokio::spawn(async move {
                let mut sma_data = SmaData::new();
                let mut sma_data_vec: Vec<SmaData> = Vec::new();

                if rt_price_data.len() >= moving_number {
                    let mut iter = rt_price_data.windows(moving_number);
                    for buffer in iter {
                        let mut avg = 0.0;
                        for element in buffer {
                            avg += element.opclo_price;
                        }
                        avg /= (moving_number as f64);

                        sma_data.sma_value = avg;
                        sma_data.close_time = buffer.last().unwrap().close_time;
                        sma_data_vec.push(sma_data.clone());
                    }
                }
                let mut sma_data_wrapper_lock = sma_data_wrapper_arc_c.lock().await;
                sma_data_wrapper_lock.insert(symbol_c, sma_data_vec.clone());
            }));
        }
    }
    try_join_all(task_vec).await?;
    let a = sma_data_wrapper_arc.lock().await.to_owned();
    Ok(a)
}
