package com.jxy.marketall.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jxy.common.core.text.Convert;
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.CoinPriceListDto;
import com.jxy.marketall.dto.DataDto;
import com.jxy.marketall.dto.PriceDataDto;
import com.jxy.marketall.entity.*;
import com.jxy.marketall.mapper.*;
import com.jxy.marketall.service.BTCService;
import com.jxy.marketall.service.CoinPriceService;
import com.jxy.marketall.service.EthBigTxService;
import com.jxy.marketall.service.NodeJsMarketFeign;
import com.jxy.marketall.vo.CoinPriceVo;
import com.jxy.marketall.vo.CoinVo;
import com.jxy.marketall.vo.QueryVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.xml.crypto.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;


/**
 * @Description 币价查询业务处理
 * @Date 2022/5/19 17:51
 * @Author 杜懿
 */
@Service
public class CoinPriceServiceImpl implements CoinPriceService {

    @Autowired
    private NodeJsMarketFeign nodeJsMarketFeign;

    @Autowired
    private RedisService redisService;

    @Autowired
    private BTC2Mapper btc2Mapper;

    @Autowired
    private BiAnMapper2 biAnMapper2;


    @Autowired
    private ETHV2Mapper ethV2Mapper;

    @Override
    public AjaxResult findCoinMarketByTime(CoinVo vo) {


        if(StringUtils.isBlank(vo.getCoin())){
            return AjaxResult.success();
        }

        if(StringUtils.isBlank(vo.getStart()) && StringUtils.isBlank(vo.getEnd())){
            Date date = new Date();
            vo.setEnd(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,date));
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.DATE,-7);
            vo.setStart(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,calendar.getTime()));
        }

        List<CoinMarketData> list = biAnMapper2.getPriceListByCoin(vo);

        List<DataDto> dataList = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            DataDto dataDto = new DataDto();
            CoinMarketData entry = list.get(i);
            dataDto.setId(entry.getId());
            dataDto.setTime(entry.getDate());
            dataDto.setValue(entry.getPrice());
            dataDto.setParam(entry.getCoinSymbol());

            dataList.add(i,dataDto);
        }

        return AjaxResult.success(dataList);
    }

    @Override
    public AjaxResult findCoinMarketAll() {

        List<CoinPriceListDto> dataList = redisService.getCacheList("coinMarketAll");

        Collections.reverse(dataList);

        return AjaxResult.success(dataList);
    }


    @Override
    public AjaxResult findCoinPriceByOHLC(CoinPriceVo coinPriceVo) {

        /** 调用查询接口 */
        List<PriceDataDto> list = getBTCPriceList(coinPriceVo);

        //构造ohlc返回值判断条件
        int monthDiff = 0;//设置默认值为0 避免计算出现
        Date start =  list.get(0).getTime();
        Date end =  list.get(list.size()-1).getTime();
        monthDiff = DateUtils.getMonthDiff(start,end);

        List<PriceDataDto> dataList = new ArrayList<>();

        /** 根据条件判断处理数据 */
        if(monthDiff <= 6){
            /** 半年 按日返回数据 */
            //for (int i = 0; i < list.size(); i++) {
            //    PriceDataDto dataDto = new PriceDataDto();
            //    PriceDataDto entry = list.get(i);
            //    dataDto.setId(entry.getId());
            //    dataDto.setTime(entry.getTime());
            //    dataDto.setValue(entry.getValue());
            //
            //    dataList.add(i,dataDto);
            //}
            return AjaxResult.success("按日返回数据",list);
        }
        else if(monthDiff <=24){
            /** 两年内 按周返回数据 */
            int startWeek = LocalDate.parse(coinPriceVo.getStart()).getDayOfWeek().getValue();

            //周数
            int week = 1;

            PriceDataDto dataDto = new PriceDataDto();
            dataDto.setValue(0.00);

            Date time = DateUtils.parseDate(coinPriceVo.getStart());

            for (int i = startWeek ; i < list.size() + startWeek; i++){

                PriceDataDto entry = list.get(i - startWeek);

                dataDto.setValue(add(dataDto.getValue(), entry.getValue()));

                if(i%7 == 0 || i== (list.size() + startWeek - 1)) {

                    String weekendTime = DateUtils.dateTime(entry.getTime());
                    dataDto.setId(week);
                    dataDto.setTime(time);
                    //统计周数据
                    int count = week - 1;
                    //System.out.println(count);
                    dataList.add(count,dataDto);

                    week++;
                    //下调数据开始时间+1
                    Date date = entry.getTime();
                    Calendar calendar = new GregorianCalendar();
                    calendar.setTime(date);
                    calendar.add(calendar.DATE,1);
                    time = calendar.getTime();

                    /** 因为复用dataDto 所有添加之后数据要还原为0 */
                    dataDto = new PriceDataDto();
                    dataDto.setValue(0.00);
                }
            }
            return AjaxResult.success("按周返回数据",dataList);
        }
        else {
            /** 两年以上 按月返回数据 */
            //判断开始时间是第几个月
            int startMonth = LocalDate.parse(coinPriceVo.getStart()).getMonthValue();

            /** 返回给前端的数据 key从1开始 value是每个月的数据（Map集合） */

            /** 每日数据 */
            PriceDataDto dataDto = new PriceDataDto();
            dataDto.setValue(0.00);

            int count = 1;

            Date time = DateUtils.parseDate(coinPriceVo.getStart());

            for (int i = 0; i < list.size(); i++) {

                PriceDataDto entry = list.get(i);

                //数据日期转为localdate
                LocalDate entryDay = entry.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                //当前月数 用于判断
                int entryMonth = entryDay.getMonthValue();

                LocalDate lastDayOfMonth = entryDay.with(TemporalAdjusters.lastDayOfMonth());
                //数据日期和当月最后一天差值 等于0表示最后一天
                int days = Period.between(entryDay, lastDayOfMonth).getDays();

                //判断
                if(entryMonth == startMonth){
                    /** 将数据加到当月数据中 */
                    dataDto.setValue(add(dataDto.getValue(),entry.getValue()));

                }

                if(days == 0 || i == (list.size() - 1)){

                    //是当月最后一天 所以下条数据月数需要变为下一个月 且要将当月数据放入返回前端的map集合
                    //数据放入返回队列
                    dataDto.setId(count);


                    //设置每天返回数据的日期为每月一号
                    Calendar ca = new GregorianCalendar();
                    ca.setTime(time);
                    ca.add(ca.MONTH,0);
                    ca.set(ca.DAY_OF_MONTH,1);
                    dataDto.setTime(ca.getTime());

                    int putId = count - 1;
                    //System.out.println(putId);
                    dataList.add(putId,dataDto);

                    //局部数据修正
                    count++;

                    if(startMonth == 12){
                        //如果已是每年最后一月 则从1开始算
                        startMonth = 0;
                    }
                    startMonth++;

                    Date date = entry.getTime();
                    Calendar   calendar = new GregorianCalendar();
                    calendar.setTime(date);
                    calendar.add(calendar.DATE,1);
                    time = calendar.getTime();

                    dataDto = new PriceDataDto();
                    dataDto.setValue(0.00);
                }
            }

            return AjaxResult.success("按月返回数据",dataList);
        }
    }

    //@Override
    //public AjaxResult findCoinPriceAllByOHLC(CoinPriceVo coinPriceVo) {
    //
    //    HashMap<String,String> map = getConditionMap(coinPriceVo);
    //
    //
    //    /** 调用查询接口 */
    //    List<Price> list = getBTCPriceList(map);
    //
    //    //构建返回数据
    //    List<DataDto> dataList = new ArrayList<>();
    //
    //    for (int i = 0; i < list.size(); i++) {
    //        DataDto dataDto = new DataDto();
    //        Price entry = list.get(i);
    //        dataDto.setId(entry.getId());
    //        dataDto.setTime(entry.getDate());
    //        dataDto.setValue(entry.getPrice());
    //
    //        dataList.add(i,dataDto);
    //    }
    //    return AjaxResult.success(dataList);
    //}

    /** 根据传参获取条件map */
    public HashMap<String,String> getConditionMap(CoinPriceVo coinPriceVo){

        HashMap<String,String> map = new HashMap<>();

        String coin = coinPriceVo.getCoin();

        /** 条件范围 */
        //if(!EnumUtils.isInclude(CoinType.class,coin)){
        //
        //    //todo 自定义异常
        //    throw new  RuntimeException("传参有误，传参不在允许范围之内");
        //}

        if(!StringUtils.isEmpty(coin)){
            //CoinType coinType = (CoinType) EnumUtils.get(CoinType.class, coin);
            //map.put("coin",coinType.getInfo());
            map.put("coin",coin.toUpperCase());
            /** 判断起止时间是否为空 */
            if(!StringUtils.isEmpty(coinPriceVo.getStart()) && !StringUtils.isEmpty(coinPriceVo.getEnd())){

                map.put("start",coinPriceVo.getStart());
                map.put("end",coinPriceVo.getEnd());

            }
        }

        return map;
    }

    /** 调用BTC或ETH的查询接口 */
    public List<PriceDataDto> getBTCPriceList(CoinPriceVo vo){


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

        if("BTC".equals(vo.getCoin())){
            list = btc2Mapper.getPriceList(vo);
        }else if ("ETH".equals(vo.getCoin())){
            list = ethV2Mapper.getPriceList(vo);
        }else {
            return null;
        }

        return list;
    }
    /** 调用其他币的查询接口 */
    public List<CoinMarketData> getCoinMarketList(HashMap<String,String> map){

        JSONObject returnDto = nodeJsMarketFeign.coinmarket(map);

        JSONArray data = JSON.parseArray(JSONObject.toJSONString(returnDto.get("data")));

        List<CoinMarketData> list = JSONObject.parseArray(data.toJSONString(),CoinMarketData.class);

        return list;
    }
    /** double求和 */
    public static double add(double v1, double v2) {

        BigDecimal b1 = new BigDecimal(Double.toString(v1));

        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.add(b2).doubleValue();

    }

}
