use crate::database_control::*;
use reqwest::{Client, ClientBuilder, Response};
use serde::Deserialize;
use serde_json::Value;

pub async fn initialize_association_record() {
    let table_name = String::from("signal_association_opinion");
    let initial_columns = vec!["name", "is_working", "opinion", "weight"];
    let initial_values = vec![
        String::from("future_ratio"),
        String::from("0"),
        String::from("-"),
        String::from("0.0"),
    ];
    insert_one_record(&table_name, &initial_columns, &initial_values).await;
}

pub async fn monitoring_future_ratio() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let client = ClientBuilder::new()
        .timeout(tokio::time::Duration::from_secs(30))
        .build()?;
    let url = "https://fapi.binance.com/futures/data/globalLongShortAccountRatio?&period=5m&symbol=BTCUSDT";
    let mut response = client.get(url).send().await;

    let mut ratio_vec: Vec<f64> = Vec::new();

    match response {
        Ok(T) => {
            let mut body = T.text_with_charset("utf-8").await;
            match body {
                Ok(T) => {
                    ratio_vec = de_json_ratio(&T).await?;
                }
                Err(E) => {
                    println!("globalLongShortAccountRatio body failed! : {:?}", E);
                }
            }
        }
        Err(E) => {
            println!("globalLongShortAccountRatio response failed!: {:?}", E);
        }
    }

    let url = "https://fapi.binance.com/futures/data/takerlongshortRatio?&symbol=BTCUSDT&period=5m";
    let mut response = client.get(url).send().await;

    let mut wrapper_vec: Vec<Vec<f64>> = Vec::new();

    match response {
        Ok(T) => {
            let mut body = T.text_with_charset("utf-8").await;
            match body {
                Ok(T) => {
                    wrapper_vec = de_json_vol(&T).await?;
                }
                Err(E) => {
                    println!("takerlongshortRatio body failed! : {:?}", E);
                }
            }
        }
        Err(E) => {
            println!("takerlongshortRatio body failed!: {:?}", E);
        }
    }

    let association_update_table_name = String::from("signal_association_opinion");
    let association_update_condition = vec![(String::from("name"), String::from("future_ratio"))];
    let mut association_update_values: Vec<(String, String)> = Vec::new();

    if ratio_vec.len() != 0 && wrapper_vec.len() != 0 {
        let mut avg_account_ratio = 0.0;
        let mut avg_vol_ratio = 0.0;
        let mut sum_sell_buy_vol = 0.0;

        ratio_vec.reverse();
        ratio_vec.truncate(6);
        ratio_vec.reverse();

        for element in &ratio_vec {
            avg_account_ratio += element;
        }
        avg_account_ratio /= ratio_vec.len() as f64;

        let mut vol_ratio_vec = wrapper_vec[0].to_vec();
        let mut buy_vol_vec = wrapper_vec[1].to_vec();
        let mut sell_vol_vec = wrapper_vec[2].to_vec();

        vol_ratio_vec.reverse();
        vol_ratio_vec.truncate(6);
        vol_ratio_vec.reverse();
        buy_vol_vec.reverse();
        buy_vol_vec.truncate(6);
        sell_vol_vec.reverse();
        sell_vol_vec.truncate(6);

        for element in &vol_ratio_vec {
            avg_vol_ratio += element;
        }

        avg_vol_ratio /= vol_ratio_vec.len() as f64;

        for element in buy_vol_vec {
            sum_sell_buy_vol += element;
        }
        for element in sell_vol_vec {
            sum_sell_buy_vol -= element;
        }

        // println!("{} {} {}", avg_account_ratio, avg_vol_ratio, sum_sell_buy_vol);
        if avg_account_ratio > 1.1 && sum_sell_buy_vol > 0.0 {
            // expect UP Trend
            association_update_values = vec![
                (String::from("is_working"), 1.to_string()),
                (String::from("opinion"), String::from("UP")),
            ];
            // println!("UP Trend");
        } else if avg_account_ratio < 1.0 {
            // expect DOWN Trend
            association_update_values = vec![
                (String::from("is_working"), 1.to_string()),
                (String::from("opinion"), String::from("DOWN")),
            ];
            // println!("Down Trend");
        } else {
            association_update_values = vec![
                (String::from("is_working"), 1.to_string()),
                (String::from("opinion"), String::from("KEEP")),
            ];
            // println!("Keep Trend");
        }
    } else {
        association_update_values = vec![
            (String::from("is_working"), 0.to_string()),
            (String::from("opinion"), String::from("-")),
        ];
    }
    update_record2(
        &association_update_table_name,
        &association_update_values,
        &association_update_condition,
    )
    .await;

    Ok(())
}

async fn de_json_ratio(
    body: &String,
) -> Result<Vec<f64>, Box<dyn std::error::Error + Send + Sync>> {
    let v: Value = serde_json::from_str(body.as_str())?;
    let mut into_vec = v.as_array();
    if into_vec == None {
        return Err("Err")?;
    }

    let mut object_map = &serde_json::map::Map::new();
    let mut ratio_vec: Vec<f64> = Vec::new();

    for element in into_vec.unwrap() {
        object_map = element.as_object().unwrap();
        let mut object_map_iter = object_map.iter();
        let result = element.get("longShortRatio");
        if result.is_some() {
            ratio_vec.push(result.unwrap().as_str().unwrap().parse::<f64>().unwrap());
        }
    }
    Ok(ratio_vec)
}

async fn de_json_vol(
    body: &String,
) -> Result<Vec<Vec<f64>>, Box<dyn std::error::Error + Send + Sync>> {
    let v: Value = serde_json::from_str(body.as_str())?;
    let mut into_vec = v.as_array();
    if into_vec == None {
        return Err("Err")?;
    }

    let mut object_map = &serde_json::map::Map::new();
    let mut buy_vol_vec: Vec<f64> = Vec::new();
    let mut sell_vol_vec: Vec<f64> = Vec::new();
    let mut ratio_vec: Vec<f64> = Vec::new();
    let mut wrapper_vec: Vec<Vec<f64>> = Vec::new();

    for element in into_vec.unwrap() {
        object_map = element.as_object().unwrap();
        let mut object_map_iter = object_map.iter();
        let result = element.get("buySellRatio");
        if result.is_some() {
            ratio_vec.push(result.unwrap().as_str().unwrap().parse::<f64>().unwrap());
        }

        let result = element.get("buyVol");
        if result.is_some() {
            buy_vol_vec.push(result.unwrap().as_str().unwrap().parse::<f64>().unwrap());
        }

        let result = element.get("sellVol");
        if result.is_some() {
            sell_vol_vec.push(result.unwrap().as_str().unwrap().parse::<f64>().unwrap());
        }
    }
    wrapper_vec.push(ratio_vec);
    wrapper_vec.push(buy_vol_vec);
    wrapper_vec.push(sell_vol_vec);

    Ok(wrapper_vec)
}
