package coin_gas_service

import (
	"bwallet/models"
	"bwallet/pkg/gredis"
	"bwallet/pkg/util"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

type Response struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data []Data `json:"data"`
}

type Data struct {
	Network  string `json:network`
	Time     int    `json:time`
	TxFee    string `json:txFee`
	GasPrice string `json:gasPrice`
}

func GetTransactionGas(name string) (map[string]interface{}, error) {
	data := make(map[string]interface{})
	//items_fee := []string{"BTC", "BCH", "LTC", "ZEC", "ZCASH", "DCR", "NEO", "TRX", "ATOM", "BTY", "ETC", "ETH", "HT", "ETHTOKEN", "BNB", "DOGE", "YCC"}
	//
	//_, found_fee := util.Contains(items_fee, strings.ToUpper(name))
	//
	//if !found_fee {
	//	return nil, errno.ErrCoinNotFound
	//}

	var coin_gas *models.CoinGas

	coin_gas, err := models.GetCoinGas(name)
	if err != nil {
		return nil, err
	}

	if coin_gas.CoinName != "" {
		data["name"] = strings.ToUpper(coin_gas.CoinName)
		data["low"] = coin_gas.Low
		data["average"] = coin_gas.Average
		data["high"] = coin_gas.High

		return data, nil
	}

	if "ETC" == strings.ToUpper(name) || "HT" == strings.ToUpper(name) {
		fee, _ := gredis.HashGet("ETC_GAS", "gasPrice", 3)
		low := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*30000*0.000000001*30*1.1, 8)
		average := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*30000*0.000000001*30*1.2, 8)
		high := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*30000*0.000000001*30*6, 8)

		data["name"] = strings.ToUpper(name)
		data["low"] = low
		data["average"] = average
		data["high"] = high
		if util.ToFloat64(high) > 0.001 {
			data["high"] = "0.001"
		}
	} else if "ETH" == strings.ToUpper(name) {
		fee, _ := gredis.HashGet(strings.ToUpper(name)+"_GAS", "gasPrice", 3)
		low := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*33000*0.000000001, 8)
		average := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*33000*0.000000001*1.1, 8)
		high := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*33000*0.000000001*6, 8)

		data["name"] = strings.ToUpper(name)
		data["low"] = low
		data["average"] = average
		data["high"] = high
		if util.ToFloat64(high) > 0.1 {
			data["high"] = "0.1"
		}
	} else if "BNB" == strings.ToUpper(name) {
		data["name"] = strings.ToUpper(name)
		data["low"] = "0.0005"
		data["average"] = "0.00125"
		data["high"] = "0.002"
	} else if "ETHTOKEN" == strings.ToUpper(name) {
		fee, _ := gredis.HashGet("ETH_GAS", "gasPrice", 3)
		low := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*130000*0.000000001, 8)
		average := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*130000*0.000000001*1.1, 8)
		high := util.FormatFloat(util.ToFloat64(string(fee))/1000000000*130000*0.000000001*6, 8)

		data["name"] = strings.ToUpper(name)
		data["low"] = low
		data["average"] = average
		data["high"] = high
		if util.ToFloat64(high) > 0.1 {
			data["high"] = "0.1"
		}
	} else {
		fee, _ := gredis.HashGet(strings.ToUpper(name)+"_GAS", "txFee", 3)
		low := util.FormatFloat(util.ToFloat64(string(fee))*1.1, 8)
		average := util.FormatFloat(util.ToFloat64(string(fee))*1.2, 8)
		high := util.FormatFloat(util.ToFloat64(string(fee))*6, 8)

		data["name"] = strings.ToUpper(name)
		data["low"] = low
		data["average"] = average
		data["high"] = high
		if "BTC" == strings.ToUpper(name) || "BCH" == strings.ToUpper(name) || "LTC" == strings.ToUpper(name) || "ZEC" == strings.ToUpper(name) || "DCR" == strings.ToUpper(name) {
			if util.ToFloat64(high) > 0.001 {
				data["high"] = "0.001"
			}
		}
		if "NEO" == strings.ToUpper(name) || "TRX" == strings.ToUpper(name) || "BTY" == strings.ToUpper(name) {
			if util.ToFloat64(high) > 1 {
				data["high"] = "1"
			}
		}
		if "ATOM" == strings.ToUpper(name) {
			if util.ToFloat64(high) > 0.01 {
				data["high"] = "0.01"
			}
		}
	}

	return data, nil
}

func Etherscan() error {
	params := make(map[string]string)
	params["module"] = "gastracker"
	params["action"] = "gasoracle"
	params["apikey"] = "ZUT8I3GGVCSBRACCCXCTGGVCPYE8WEID6S"

	req, err := http.NewRequest(http.MethodGet, "https://api-cn.etherscan.com/api", nil)
	if err != nil {
		return err
	}
	condition := make(url.Values)
	condition.Add("module", params["module"])
	condition.Add("action", params["action"])
	condition.Add("apikey", params["apikey"])

	req.URL.RawQuery = condition.Encode()
	r, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	result := map[string]interface{}{}
	json.Unmarshal(body, &result)

	eth_gas, _ := result["result"].(map[string]interface{})

	gredis.HashSet("ETH_GAS", "Low", eth_gas["SafeGasPrice"], 3)
	gredis.HashSet("ETH_GAS", "Average", eth_gas["ProposeGasPrice"], 3)
	gredis.HashSet("ETH_GAS", "High", eth_gas["FastGasPrice"], 3)

	final := 21000 * util.ToFloat32(eth_gas["SafeGasPrice"]) * 0.000000001
	gredis.HashSet("ETH_GAS", "Final", final, 3)

	return nil
}

func Btcscan() error {
	req, err := http.NewRequest(http.MethodGet, "https://btc.com/service/fees/recommended", nil)
	if err != nil {
		return err
	}

	r, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	result := map[string]interface{}{}
	json.Unmarshal(body, &result)

	btc_gas, _ := result["data"].(map[string]interface{})
	gredis.HashSet("BTC_GAS", "Low", btc_gas["one_block_fee"], 3)
	gredis.HashSet("BTC_GAS", "Average", btc_gas["one_block_fee"], 3)
	gredis.HashSet("BTC_GAS", "High", btc_gas["one_block_fee"], 3)

	final := util.ToFloat32(btc_gas["one_block_fee"]) * (1 + 0.1) * 0.00001
	gredis.HashSet("BTC_GAS", "Final", final, 3)

	return nil
}

func TokenView() error {
	req, err := http.NewRequest(http.MethodGet, "https://tokenview.com/api/block/latest", nil)
	if err != nil {
		return err
	}

	r, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	responseData, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	var responseObject Response
	json.Unmarshal(responseData, &responseObject)

	for _, val := range responseObject.Data {
		if "-" == val.TxFee || "-" == val.GasPrice {
			continue
		}
		if "BTC" == strings.ToUpper(val.Network) {
			gredis.HashSet("BTC_GAS", "txFee", val.TxFee, 3)
			gredis.HashSet("BTC_GAS", "time", val.Time, 3)
		}
		if "BCH" == strings.ToUpper(val.Network) {
			gredis.HashSet("BCH_GAS", "txFee", val.TxFee, 3)
			gredis.HashSet("BCH_GAS", "time", val.Time, 3)
		}
		if "LTC" == strings.ToUpper(val.Network) {
			gredis.HashSet("LTC_GAS", "txFee", val.TxFee, 3)
			gredis.HashSet("LTC_GAS", "time", val.Time, 3)
		}
		if "ZCASH" == strings.ToUpper(val.Network) || "ZEC" == strings.ToUpper(val.Network) {
			gredis.HashSet("ZEC_GAS", "txFee", val.TxFee, 3)
			gredis.HashSet("ZEC_GAS", "time", val.Time, 3)
		}
		if "DCR" == strings.ToUpper(val.Network) {
			gredis.HashSet("DCR_GAS", "txFee", val.TxFee, 3)
			gredis.HashSet("DCR_GAS", "time", val.Time, 3)
		}
		if "DOGE" == strings.ToUpper(val.Network) {
			gredis.HashSet("DOGE_GAS", "txFee", val.TxFee, 3)
			gredis.HashSet("DOGE_GAS", "time", val.Time, 3)
		}
		if "ETC" == strings.ToUpper(val.Network) {
			gredis.HashSet("ETC_GAS", "gasPrice", val.GasPrice, 3)
			gredis.HashSet("ETC_GAS", "time", val.Time, 3)
			gredis.HashSet("HT_GAS", "gasPrice", val.GasPrice, 3)
			gredis.HashSet("HT_GAS", "time", val.Time, 3)
		}
		if "ETH" == strings.ToUpper(val.Network) {
			gredis.HashSet("ETH_GAS", "gasPrice", val.GasPrice, 3)
			gredis.HashSet("ETH_GAS", "time", val.Time, 3)
		}
	}
	return nil
}

type CoinGas struct {
	Id       int
	CoinName string
	Low      string
	Average  string
	High     string
}

func (g *CoinGas) GetAll() ([]*models.CoinGas, error) {
	coins_gas, err := models.GetCoinsGas(g.getMaps())
	if err != nil {
		return nil, err
	}

	return coins_gas, nil
}

func (g *CoinGas) Add() error {
	coinGas := map[string]interface{}{
		"coin_name": g.CoinName,
		"low":       g.Low,
		"average":   g.Average,
		"high":      g.High,
	}

	if err := models.AddCoinGas(coinGas); err != nil {
		return err
	}

	return nil
}

func (g *CoinGas) Edit() error {
	return models.EditCoinGas(g.getMaps(), map[string]interface{}{
		"low":     g.Low,
		"average": g.Average,
		"high":    g.High,
	})
}

func (g *CoinGas) Delete() error {
	return models.DeleteCoinGas(g.Id)
}

func (g *CoinGas) ExistCoinGasByName() (bool, error) {
	return models.ExistCoinGasByName(g.CoinName)
}

func (g *CoinGas) ExistCoinGasById() (bool, error) {
	return models.ExistCoinGasById(g.Id)
}

func (c *CoinGas) getMaps() (map[string]interface{}) {
	maps := make(map[string]interface{})

	if c.CoinName != "" {
		maps["coin_name"] = c.CoinName
	}

	if c.Id != 0 {
		maps["id"] = c.Id
	}

	return maps
}
