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

use crate::database_control::*;
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
use crate::strategy_team::FilteredData;
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: &Vec<(String, Vec<RealtimePriceData>)>,
    filtered_symbols: &Vec<FilteredData>,
) -> Result<Vec<(String, Vec<SmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
    if filtered_symbols.is_empty() {
        Err("Err")?;
    }

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

    let mut task_vec = Vec::new();
    for filtered_symbol in filtered_symbols {
        let filtered_symbol_c = filtered_symbol.clone();
        let sma_data_wrapper_arc_c = Arc::clone(&sma_data_wrapper_arc);
        let input_rt_data_c = input_rt_data.clone();
        task_vec.push(tokio::spawn(async move {
            let search_result = input_rt_data_c.iter().position(|x| x.0 == *filtered_symbol_c.symbol);
            if search_result.is_some() {
                let mut sma_data = SmaData::new();
                let mut sma_data_vec: Vec<SmaData> = Vec::new();
                
                if input_rt_data_c[search_result.unwrap()].1.len() >= moving_number {
                    let mut iter = input_rt_data_c[search_result.unwrap()].1.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.push((filtered_symbol_c.symbol.clone(), 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: &Vec<(String, Vec<RealtimePriceData>)>,
    filtered_symbols: &Vec<FilteredData>,
) -> Result<Vec<(String, Vec<SmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
    if filtered_symbols.is_empty() {
        Err("Err")?;
    }

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

    let mut task_vec = Vec::new();
    for filtered_symbol in filtered_symbols {
        let filtered_symbol_c = filtered_symbol.clone();
        let sma_data_wrapper_arc_c = Arc::clone(&sma_data_wrapper_arc);
        let input_rt_data_c = input_rt_data.clone();
        task_vec.push(tokio::spawn(async move {
            let search_result = input_rt_data_c.iter().position(|x| x.0 == *filtered_symbol_c.symbol);
            if search_result.is_some() {
                let mut sma_data = SmaData::new();
                let mut sma_data_vec: Vec<SmaData> = Vec::new();
                
                if input_rt_data_c[search_result.unwrap()].1.len() >= moving_number {
                    let mut iter = input_rt_data_c[search_result.unwrap()].1.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.push((filtered_symbol_c.symbol.clone(), sma_data_vec.clone()));
            }
        }));
    }
    try_join_all(task_vec).await?;
    let a = sma_data_wrapper_arc.lock().await.to_owned();
    Ok(a)
}
