package com.jxy.marketall.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jxy.common.core.utils.DateUtils;
import com.jxy.common.core.utils.StringUtils;
import com.jxy.common.core.web.Result.AjaxResult;
import com.jxy.common.redis.service.RedisService;
import com.jxy.marketall.dto.*;
import com.jxy.marketall.entity.BTCTags;
import com.jxy.marketall.entity.ExchangeBalance;
import com.jxy.marketall.mapper.BTCNewV2Mapper;
import com.jxy.marketall.mapper.BTCV2Mapper;
import com.jxy.marketall.service.BTCV2Service;
import com.jxy.marketall.vo.EBalanceVo;
import com.jxy.marketall.vo.QueryVo;
import com.jxy.marketall.vo.SmaVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Date 2023/1/13 10:58
 * @Author 杜懿
 */
@Service
public class BTCV2ServiceImpl implements BTCV2Service {

    @Autowired
    private BTCNewV2Mapper btcNewV2Mapper;

    @Autowired
    private RedisService redisService;

    @Override
    public AjaxResult getProfitAddressesList(int sma) {
        List<DateBigDecimalDto> list = getList("ProfitAddressList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getLossAddressList(int sma) {
        List<DateBigDecimalDto> list = getList("LossAddressList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getProfitRatioList(int sma) {
        List<DateBigDecimalDto> list = getList("ProfitRatioList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getLthSupplyList(int sma) {
        List<DateBigDecimalDto> list = getList("LthSupplyList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getSthSupplyList(int sma) {
        List<DateBigDecimalDto> list = getList("SthSupplyList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getRealizedPriceList(int sma) {
        List<DateBigDecimalDto> list = getList("RealizedPriceList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getRelativeSupplyList(int sma) {
        List<DateBigDecimalDto> list = getList("RelativeSupplyList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getLthSthSupplyDistributionList(int sma) {
        //todo
        List<RelativeSupplyDto> list = redisService.getCacheList("LthSthSupplyDistributionList");
        if(list.size() < 1){
            return AjaxResult.success(list);
        }

        if(sma > 0){
            List<RelativeSupplyDto> returnList = new ArrayList<>();
            if (list.size()< sma){
                return AjaxResult.success(returnList);
            }

            BigDecimal lls = BigDecimal.ZERO;
            BigDecimal lps = BigDecimal.ZERO;
            BigDecimal sls = BigDecimal.ZERO;
            BigDecimal sps = BigDecimal.ZERO;
            BigDecimal divideNumber = new BigDecimal(sma);
            for(int i = 0 ; i < sma ;i++){
                lls =  list.get(i).getLthLossSupply().add(lls);
                lps =  list.get(i).getLthProfitSupply().add(lps);
                sls =  list.get(i).getSthLossSupply().add(sls);
                sps =  list.get(i).getSthProfitSupply().add(sps);
            }
            BigDecimal startLLS = lls.divide(divideNumber, 8, BigDecimal.ROUND_HALF_UP);
            BigDecimal startLPS = lps.divide(divideNumber, 8, BigDecimal.ROUND_HALF_UP);
            BigDecimal startSLS = sls.divide(divideNumber, 8, BigDecimal.ROUND_HALF_UP);
            BigDecimal startSPS = sps.divide(divideNumber, 8, BigDecimal.ROUND_HALF_UP);

            RelativeSupplyDto startDto = new RelativeSupplyDto();
            startDto.setDate(list.get(sma-1).getDate());
            startDto.setLthLossSupply(startLLS.stripTrailingZeros());
            startDto.setLthProfitSupply(startLPS.stripTrailingZeros());
            startDto.setSthLossSupply(startSLS.stripTrailingZeros());
            startDto.setSthProfitSupply(startSPS.stripTrailingZeros());

            returnList.add(startDto);
            for (int i = sma; i < list.size(); i++) {

                lls = lls.add(list.get(i).getLthLossSupply()).subtract(list.get(i-sma).getLthLossSupply());
                lps = lps.add(list.get(i).getLthProfitSupply()).subtract(list.get(i-sma).getLthProfitSupply());
                sls = sls.add(list.get(i).getSthLossSupply()).subtract(list.get(i-sma).getSthLossSupply());
                sps = sps.add(list.get(i).getSthProfitSupply()).subtract(list.get(i-sma).getSthProfitSupply());

                startLLS = lls.divide(divideNumber,8, BigDecimal.ROUND_HALF_UP);
                startLPS = lps.divide(divideNumber,8, BigDecimal.ROUND_HALF_UP);
                startSLS = sls.divide(divideNumber,8, BigDecimal.ROUND_HALF_UP);
                startSPS = sps.divide(divideNumber,8, BigDecimal.ROUND_HALF_UP);

                RelativeSupplyDto dto = new RelativeSupplyDto();
                dto.setDate(list.get(i).getDate());
                //返回给前端的参数需要删除多余的0
                dto.setLthLossSupply(startLLS.stripTrailingZeros());
                dto.setLthProfitSupply(startLPS.stripTrailingZeros());
                dto.setSthLossSupply(startSLS.stripTrailingZeros());
                dto.setSthProfitSupply(startSPS.stripTrailingZeros());

                returnList.add(dto);
            }
            return AjaxResult.success(returnList);
        }
        return AjaxResult.success(list);
    }

    @Override
    public AjaxResult getLthProfitSupplyList(int sma) {
        List<DateBigDecimalDto> list = getList("LthProfitSupplyList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getSthProfitSupplyList(int sma) {
        List<DateBigDecimalDto> list = getList("SthProfitSupplyList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getLthLossSupplyList(int sma) {
        List<DateBigDecimalDto> list = getList("LthLossSupplyList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getSthLossSupplyList(int sma) {
        List<DateBigDecimalDto> list = getList("SthLossSupplyList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getSthProfitRatioList(int sma) {
        List<DateBigDecimalDto> list = getList("SthProfitRatioList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getLthProfitRatioList(int sma) {
        List<DateBigDecimalDto> list = getList("LthProfitRatioList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getSLRVRatioList(int sma) {
        List<DateBigDecimalDto> list = getList("SLRVRatioList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getLthVolumeList(int sma) {
        List<DateBigDecimalDto> list = getList("LthVolumeList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getFeeRatioMultipleList(int sma) {
        List<DateBigDecimalDto> list = getList("FeeRatioMultipleList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getCumulativeValueDaysDestroyedList(int sma) {
        List<DateBigDecimalDto> list = getList("CVDDList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getBalancedPriceList(int sma) {
        List<DateBigDecimalDto> list = getList("BalancedPriceList", sma);
        return  AjaxResult.success(list);}

    @Override
    public AjaxResult getNVTRatioList(int sma) {
        List<DateBigDecimalDto> list = getList("NVTRatioList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getVelocityList(int sma) {

        List<DateBigDecimalDto> list = getList("VelocityList", sma);
        return  AjaxResult.success(list);

    }

    @Override
    public AjaxResult getPiCycleTIList(QueryVo vo) {

        List<PiCycleTIDto> list = redisService.getCacheList("BTCPiCTIList");

        if(list.size() < 1){
            return AjaxResult.success(list);
        }

        if(StringUtils.isNotEmpty(vo.getStart())){
            Date start = DateUtils.parseDate(vo.getStart());
            list = list.stream().filter(dto -> (dto.getDate().after(start) || dto.getDate().equals(start))).collect(Collectors.toList());
        }

        if(StringUtils.isNotEmpty(vo.getEnd())){
            Date end = DateUtils.parseDate(vo.getEnd());
            list = list.stream().filter(dto -> (dto.getDate().before(end) || dto.getDate().equals(end))).collect(Collectors.toList());
        }

        if(vo.getSma() > 0){
            // TODO:
        }

        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getSSRList() {
        List<DateBigDecimalDto> list = getList("StablecoinSupplyRatioList",0);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getSSROList(int sma) {
        List<DateBigDecimalDto> list = getList("StablecoinSupplyRatioOscillatorList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getSTFRatioList(QueryVo vo) {

        List<DateBigDecimalDto> list = getList("STFRatioList",vo.getSma());

        if(list.size() < 1){
            return AjaxResult.success(list);
        }

        if(StringUtils.isNotEmpty(vo.getStart())){
            Date start = DateUtils.parseDate(vo.getStart());
            list = list.stream().filter(dto -> (dto.getDate().after(start) || dto.getDate().equals(start))).collect(Collectors.toList());
        }

        if(StringUtils.isNotEmpty(vo.getEnd())){
            Date end = DateUtils.parseDate(vo.getEnd());
            list = list.stream().filter(dto -> (dto.getDate().before(end) || dto.getDate().equals(end))).collect(Collectors.toList());
        }

        return  AjaxResult.success(list);

    }

    @Override
    public AjaxResult getSTFDeflectionList(int sma) {
        List<DateBigDecimalDto> list = getList("STFRatioDeflectionList", sma);
        return  AjaxResult.success(list);
    }

    @Override
    public AjaxResult getGoldenRatioMultList(int sma) {

        List<GoldenRatioMultiplierDto> list = redisService.getCacheList("BTCGoldenRatioMultiplierList");

        if(list.size() < 1){
            return AjaxResult.success(list);
        }

        if(sma > 0){
            //todo sma处理
            //返回处理过的数据
            //return AjaxResult.success(list);
        }

        return AjaxResult.success(list);
    }

    @Override
    public AjaxResult getMempoolTransaction(QueryVo vo) {

        List<MempoolTransactionDto> list = redisService.getCacheList("MempoolTransationList");

        if(list.size() < 1){
            return AjaxResult.success(list);
        }

        if(vo.getSma() > 30){
            list = new ArrayList<>();
            return AjaxResult.success("当前指标移动平均天数不能大于30天！",list);
        }

        int sma = vo.getSma();
        if(vo.getSma() > 0){

            BigDecimal size = BigDecimal.ZERO;
            BigDecimal fees = BigDecimal.ZERO;
            BigDecimal divideNumber = new BigDecimal(sma);

            for(int i = 0 ; i < sma ;i++){
                size =  list.get(i).getMempoolSize().add(size);
                fees =  list.get(i).getMempoolFees().add(fees);
            }
            BigDecimal startSize = size.divide(divideNumber, 8, BigDecimal.ROUND_HALF_UP);
            BigDecimal startFees = fees.divide(divideNumber, 8, BigDecimal.ROUND_HALF_UP);
            MempoolTransactionDto startDto = new MempoolTransactionDto();
            startDto.setDate(list.get(sma-1).getDate());
            startDto.setMempoolSize(startSize.stripTrailingZeros());
            startDto.setMempoolFees(startFees.stripTrailingZeros());

            List<MempoolTransactionDto> returnList = new ArrayList<>();
            returnList.add(startDto);
            for (int i = sma; i < list.size(); i++) {

                size = size.add(list.get(i).getMempoolSize()).subtract(list.get(i-sma).getMempoolSize());

                fees = fees.add(list.get(i).getMempoolFees()).subtract(list.get(i-sma).getMempoolFees());

                startSize = size.divide(divideNumber,8, BigDecimal.ROUND_HALF_UP);

                startFees = fees.divide(divideNumber,8, BigDecimal.ROUND_HALF_UP);

                MempoolTransactionDto dto = new MempoolTransactionDto();
                dto.setDate(list.get(i).getDate());
                //返回给前端的参数需要删除多余的0
                dto.setMempoolSize(startSize.stripTrailingZeros());
                dto.setMempoolFees(startFees.stripTrailingZeros());

                returnList.add(dto);
            }
            //return returnList;
        }

        return AjaxResult.success(list);
    }



    @Override
    public AjaxResult getExchanges() {
        Set<String> exchanges = redisService.getCacheSet("BTCExchanges");
        if(exchanges.size() < 1){
            return AjaxResult.success(exchanges);
        }
        return AjaxResult.success(exchanges);
    }

    @Override
    public AjaxResult getExchangeBalance(EBalanceVo vo) {

        Map<String,List<DateBigDecimalDto>> map = redisService.getCacheMap("BTCExchangeBalanceMap");

        if (map.size() < 1){
            return AjaxResult.success(new ArrayList<>());
        }

        List<DateBigDecimalDto> list = map.get(vo.getExchange());

        if(list.size() < 1){
            return AjaxResult.success("获取数据为空,请检查参数是否异常",list);
        }

        if(vo.getSma() > 0){
            list = getSMA(list, vo.getSma());
        }
        return AjaxResult.success(list);
    }

    @Override
    public AjaxResult getNVTSignalList(int sma) {
        List<DateBigDecimalDto> list =getList("NVTSignList",sma);
        //市值marketcap /交易量volume
        return  AjaxResult.success(list);
    }


    public List<DateBigDecimalDto> getList(String key,int sma){

        List<DateBigDecimalDto> list = new ArrayList<>();

        if(redisService.hasKey(key)){
            list = redisService.getCacheList(key);
        }

        if(sma > 0){
            //todo sma处理
            list = getSMA(list,sma);
            //返回处理过的数据
            //return AjaxResult.success(list);
        }

        return list;
    }

    /**
     * sma处理
     * @param list
     * @return
     */
    public List<DateBigDecimalDto> getSMA(List<DateBigDecimalDto> list,int day) {

        if (list.size()< day){
            return new ArrayList<>();
        }

        if(list.size() < 1){
            return list;
        }

        BigDecimal total = BigDecimal.ZERO;
        BigDecimal divideNumber = new BigDecimal(day);
        for(int i = 0 ; i < day ;i++){
            total =  list.get(i).getValue().add(total);
        }
        BigDecimal startY = total.divide(divideNumber, 8, BigDecimal.ROUND_HALF_UP);
        DateBigDecimalDto startDto = new DateBigDecimalDto();
        startDto.setDate(list.get(day-1).getDate());
        startDto.setValue(startY.stripTrailingZeros());

        List<DateBigDecimalDto> returnList = new ArrayList<>();
        returnList.add(startDto);
        for (int i = day; i < list.size(); i++) {

            total = total.add(list.get(i).getValue()).subtract(list.get(i-day).getValue());

            startY = total.divide(divideNumber,8, BigDecimal.ROUND_HALF_UP);

            DateBigDecimalDto dto = new DateBigDecimalDto();
            dto.setDate(list.get(i).getDate());
            //返回给前端的参数需要删除多余的0
            dto.setValue(startY.stripTrailingZeros());

            returnList.add(dto);
        }
        return returnList;
    }

}
