package com.oraclechain.eosio.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.oraclechain.eosio.dto.NewDexTicker;
import com.oraclechain.eosio.eosApi.GetCurrencyInfo;
import com.oraclechain.eosio.constants.Variables;
import com.oraclechain.eosio.dto.ExchangeRate;
import com.oraclechain.eosio.dto.UserAsset;
import com.oraclechain.eosio.exceptions.ErrorCodeEnumChain;
import com.oraclechain.eosio.exceptions.ExceptionsChain;
import com.oraclechain.eosio.service.RedisService;
import com.oraclechain.eosio.service.BlockServiceEos;
import com.oraclechain.eosio.utils.EosTxUtils;
import com.oraclechain.eosio.utils.HttpClientUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;


@Slf4j
@Service
public class BlockServiceEosImpl implements BlockServiceEos {


    @Resource
    private RedisService redisService;


    public BigDecimal getBalance(String baseUrl,
                                 String contractName,
                                 String tokenSymbol,
                                 String accountName) throws Exception
    {

        GetCurrencyInfo currencyInfo = new GetCurrencyInfo();
        currencyInfo.setAccount(accountName);
        currencyInfo.setCode(contractName);
        currencyInfo.setSymbol(tokenSymbol);
        String json = new Gson().toJson(currencyInfo);
        String result= HttpClientUtils.ocPost(Variables.eosChainUrl+ "get_currency_balance", json);
        //should NOT add handleEosResponse here

        BigDecimal token_balance = null;
        JsonElement data = new JsonParser().parse(result);
        if(data.isJsonArray())
        {
            JsonArray arr_obj = data.getAsJsonArray();
            for(int i=0 ; i< arr_obj.size(); i++)
            {
                token_balance = EosTxUtils.translateToken(arr_obj.get(i).getAsString(), tokenSymbol);
            }
        }


        if(token_balance == null)
        {
            token_balance = new BigDecimal("0");
        }
        return token_balance;

    }



    private NewDexTicker getNewDexTicker(String coinmarket_id) throws Exception
    {
        StringBuilder req_url = new StringBuilder();


        String redis_key = Variables.redisKeyPrefixBlockchain+ Variables.redisKeyEosNewdexMid + coinmarket_id;
        NewDexTicker newDexTicker = redisService.get(redis_key, NewDexTicker.class);
        if(newDexTicker == null){
            try{
                req_url.append(Variables.NEWDEX_TICKER).append("?symbol=").append(coinmarket_id);
                String result = HttpClientUtils.ocGet(req_url.toString());
                JsonElement data = new JsonParser().parse(result);
                if(data.isJsonObject()){
                    newDexTicker = new Gson().fromJson(data.getAsJsonObject().get("data").toString(), NewDexTicker.class);
                    redisService.set(redis_key, newDexTicker, Variables.redisCacheTimeout);
                }
            }
            catch (Exception e)
            {
                //不再抛出错误,直接初始化为零
                newDexTicker = new NewDexTicker();
//                throw new ExceptionsChain(ErrorCodeEnumChain.unknown_new_dex_exception);
            }
        }
        return newDexTicker;
    }

    private ExchangeRate getBaseTicker(String coinmarket_id) throws Exception
    {

        StringBuilder req_url = new StringBuilder();



        String redis_key = Variables.redisKeyPrefixBlockchain+ Variables.redisKeyEosCoinmarketcapMid + coinmarket_id;
        ExchangeRate coinMarketTicker = redisService.get(redis_key, ExchangeRate.class);
        if(coinMarketTicker == null){
            try{
                req_url.append(Variables.COINMARKETCAP_TICKER).append(coinmarket_id).append("?convert=CNY");
                String result = HttpClientUtils.get(req_url.toString(), "UTF-8");
                coinMarketTicker  = JSON.parseArray(result, ExchangeRate.class).get(0);
                redisService.set(redis_key, coinMarketTicker, Variables.redisCacheTimeout);
            }
            catch (Exception e)
            {
                //不再抛出错误,直接初始化为零
                coinMarketTicker = new ExchangeRate();
//                throw new ExceptionsChain(ErrorCodeEnumChain.unknown_market_id_exception);
            }
        }
        return coinMarketTicker;
    }



    public ExchangeRate getRate(String external_id) throws Exception{

        //处理异常情况
        if(external_id == null || external_id.isEmpty() || external_id.length()> 12){
            return new ExchangeRate();
        }

        //获取eos
        ExchangeRate exchangeRate = getBaseTicker(Variables.COINMARKETCAP_ID_EOS);
        if(external_id.equals("eos") ){
            return exchangeRate;
        }

        BigDecimal eos_to_cny = new BigDecimal(exchangeRate.getPrice_cny());
        BigDecimal eos_to_usd = new BigDecimal(exchangeRate.getPrice_usd());

        //获取newdex
        NewDexTicker newDexTicker = getNewDexTicker(external_id);
        log.info("--->get_rate success:" + newDexTicker.toString());

        //获取兑换EOS中间价
        BigDecimal coin_to_eos = new BigDecimal(newDexTicker.getLast());
        BigDecimal volume_to_eos = new BigDecimal(newDexTicker.getVolume());

        //转换中间价为货币
        BigDecimal coin_to_cny = coin_to_eos.multiply(eos_to_cny);
        BigDecimal coin_to_usd = coin_to_eos.multiply(eos_to_usd);
        BigDecimal volume_to_cny = volume_to_eos.multiply(eos_to_cny);
        BigDecimal volume_to_usd = volume_to_eos.multiply(eos_to_usd);

        //
        exchangeRate.setId(external_id);
        exchangeRate.setPercent_change_24h(newDexTicker.getChange());
        exchangeRate.setPrice_cny(coin_to_cny.setScale(4, RoundingMode.DOWN).toPlainString());
        exchangeRate.setPrice_usd(coin_to_usd.setScale(4, RoundingMode.DOWN).toPlainString());
        exchangeRate.setMarket_cap_cny(volume_to_cny.setScale(4, RoundingMode.DOWN).toPlainString());
        exchangeRate.setMarket_cap_usd(volume_to_usd.setScale(4, RoundingMode.DOWN).toPlainString());
        return exchangeRate;

    }


    public UserAsset getUserAssetInfo(String baseUrl,
                                      String accountName,
                                      String contractName,
                                      String tokenSymbol,
                                      String coinmarket_id) throws Exception
    {


        ExchangeRate exchangeRate = getRate(coinmarket_id);


        //根据ticker换算成货币
        UserAsset userAssetInfo = new UserAsset();
        userAssetInfo.setAccount_name(accountName);
        userAssetInfo.setContract_name(contractName);
        userAssetInfo.setToken_symbol(tokenSymbol);
        userAssetInfo.setCoinmarket_id(coinmarket_id);

        userAssetInfo.setAsset_market_cap_cny(exchangeRate.getMarket_cap_cny());
        userAssetInfo.setAsset_market_cap_usd(exchangeRate.getMarket_cap_usd());
        userAssetInfo.setAsset_price_change_in_24h(exchangeRate.getPercent_change_24h());


        BigDecimal eos_usd_price = new BigDecimal(exchangeRate.getPrice_usd());
        BigDecimal eos_cny_price = new BigDecimal(exchangeRate.getPrice_cny());
        userAssetInfo.setAsset_price_usd(eos_usd_price.setScale(4, RoundingMode.DOWN).toPlainString());
        userAssetInfo.setAsset_price_cny(eos_cny_price.setScale(4, RoundingMode.DOWN).toPlainString());


        BigDecimal token_balance = getBalance(
                baseUrl,
                contractName,
                tokenSymbol,
                accountName);

        userAssetInfo.setBalance(token_balance.toPlainString());
        userAssetInfo.setBalance_usd(token_balance.multiply(eos_usd_price).setScale(4, RoundingMode.DOWN).toPlainString());
        userAssetInfo.setBalance_cny(token_balance.multiply(eos_cny_price).setScale(4, RoundingMode.DOWN).toPlainString());



        return userAssetInfo;
    }



}