package com.m2pool.oapi.service.impl;

import com.m2pool.common.core.text.Convert;
import com.m2pool.common.core.utils.DateUtils;
import com.m2pool.common.core.utils.StringUtils;
import com.m2pool.common.core.web.Result.AjaxResult;
import com.m2pool.oapi.dto.*;
import com.m2pool.oapi.entity.MinerState;
import com.m2pool.oapi.enums.PoolAmount;
import com.m2pool.oapi.enums.PoolUnits;
import com.m2pool.oapi.mapper.PoolMapper;
import com.m2pool.oapi.service.PoolService;
import com.m2pool.oapi.utils.EnumUtils;
import com.m2pool.oapi.vo.CoinVo;
import com.m2pool.oapi.vo.DateVo;
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 2024/9/13 10:44
 * @Author 杜懿
 */
@Service
public class PoolServiceImpl implements PoolService {

    @Autowired
    private PoolMapper poolMapper;

    @Override
    public AjaxResult getHashRate(CoinVo vo) {
        PoolUnits unit = (PoolUnits) EnumUtils.get(PoolUnits.class, vo.getCoin());
        if(StringUtils.isNull(unit)){
            return AjaxResult.error("coin error");
        }

        HashRateRealDto dto = poolMapper.getPoolRealHashRateListByCoin(vo);

        dto.setUnit(unit.getUnit());

        return AjaxResult.success(dto);
    }

    @Override
    public AjaxResult getHashRateHistory(DateVo vo) {
        if(StringUtils.isNull(vo)){
            return AjaxResult.error("request body cannot be null");
        }

        PoolUnits unit = (PoolUnits) EnumUtils.get(PoolUnits.class, vo.getCoin());
        if(StringUtils.isNull(unit)){
            return AjaxResult.error("coin error");
        }

        Date today = new Date();
        today.setHours(0);
        today.setMinutes(0);
        today.setMinutes(0);

        Calendar ca = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        ca.setTime(today);
        ca.add(Calendar.MONTH,-3);

        //只允许查询当前日期之前3个月的记录 所以firstDate代表运行查询是最早时间值
        Date firstDate = ca.getTime();
        //用start保存最开始用户传入的开始时间 没传start或者错误格式都会导致start为null 后续可以根据start是否为空判断是否有正确传入开始时间
        Date start = DateUtils.parseDate(vo.getStart());

        Date end = DateUtils.parseDate(vo.getEnd());

        if (StringUtils.isNotNull(end)){
            //在三个月之内 不做处理
            if(StringUtils.isNull(start)){
                //用户没传start 只需比较end 和 firsrDate
                if(end.before(firstDate) || end.equals(firstDate)){
                    return AjaxResult.error("end Date can not before "+DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,firstDate));
                }
                //end 在firstDate之后 符合条件 可以进入后续步骤
            }else {
                //用户传了 start 此时有start 和 end以及firstDate 需要优先比较这两个start和end是否符合 start before end
                if(end.before(start) || end.equals(start)){
                    return AjaxResult.error("end Date must after start Date");
                }else {
                    //start before end  此时可能的时间顺序有  1、firstDate start end  2、start firstDate end 3、 start end firstDate
                    //第一种情况则正常按用户传的start、end查询 即不做处理
                    //第二种情况则设vo.start为firstDate
                    //第三种情况提示 end 不能在firstDate之前
                    if(start.before(firstDate)){
                        //满足次条件的只有2和3 3会在后面进行拦截 所以此处不用处理
                        //处理第二种情况
                        vo.setStart(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,firstDate));
                    }

                    //执行到这里只有1、修正了时间的2 以及3
                    if(end.before(firstDate)){
                        //
                        return AjaxResult.error("end Date can not before "+DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,firstDate));
                    }
                }
            }
        }else {
            //没有end
            if(StringUtils.isNotNull(start) && firstDate.before(start)){
                //只有用户传入了正确格式的开始时间 并且这个时间在firstDate之后才不用修改vo.start 否则都需要设置vo.start为firstDate
            }else {
                vo.setStart(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,firstDate));
            }

        }
        List<HashRateDto> mhs24hList = poolMapper.getPoolHashRateHistory24hListByCoin(vo);
        List<HashRateDto> mhs30mList = poolMapper.getPoolHashRateHistory30mListByCoin(vo);
        PoolHashRateHistoryDto dto = new PoolHashRateHistoryDto();
        dto.setMhs24hList(mhs24hList);
        dto.setMhsList(mhs30mList);
        dto.setUnit(unit.getUnit());

        return AjaxResult.success(dto);
    }

    @Override
    public AjaxResult getMinersList(CoinVo vo) {
        PoolUnits unit = (PoolUnits) EnumUtils.get(PoolUnits.class, vo.getCoin());
        if(StringUtils.isNull(unit)){
            //防止coin注入异常数据
            return AjaxResult.error("coin error");
        }

        MinerWatchDto dto = new MinerWatchDto();
        List<MinerState> list = poolMapper.getMinerListByCoin(vo);
        Map<String, Long> map = list.stream().collect(Collectors.groupingBy(
                MinerState::getState,
                Collectors.counting()
        ));

        long total = Convert.toLong(list.size(),0L);
        long online = map.getOrDefault("online", 0L);
        long offline = map.getOrDefault("offline", 0L);
        dto.setTotal(total);
        dto.setOnline(online);
        dto.setOffline(offline);
        dto.setTimeout(BigDecimal.valueOf(total)
                .subtract(BigDecimal.valueOf(online))
                .subtract(BigDecimal.valueOf(offline))
                .longValue());

        return AjaxResult.success(dto);
    }

    @Override
    public AjaxResult getWatch(CoinVo vo) {
        PoolUnits unit = (PoolUnits) EnumUtils.get(PoolUnits.class, vo.getCoin());
        if(StringUtils.isNull(unit)){
            //防止coin注入异常数据
            return AjaxResult.error("coin error");
        }

        PoolAmount poolAmount = (PoolAmount) EnumUtils.get(PoolAmount.class, vo.getCoin());
        if(StringUtils.isNull(poolAmount)){
            //防止coin注入异常数据
            return AjaxResult.error("coin error");
        }

        PoolWatchDto watch = poolMapper.getPoolWatchByCoin(vo);
        if(StringUtils.isNull(watch)){
            watch = new PoolWatchDto();
            watch.setMiners(0);
            watch.setMhs(BigDecimal.ZERO);
            watch.setHeight(0);
        }
        //todo  加到配置文件中
        int fee = 1;
        if("enx".equals(vo.getCoin())){
            Date now =new Date();
            if(now.before(DateUtils.parseDate("2025-04-21"))){{
                fee =0;
            }}
        }
        watch.setFee(fee+"% PPLNS");
        watch.setMinPay(poolAmount.getAmount());

        DateVo dateVo = new DateVo();
        dateVo.setCoin(vo.coin);
        //Date today = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getDate());
        Date today = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getDate()+" 00:00:00");

        Calendar ca = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        ca.setTime(today);
        ca.add(Calendar.DATE,-7);

        Date start = ca.getTime();
        dateVo.setStart(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,start));
        List<HashRateDto> list = poolMapper.getPoolHashRateHistory24hListByCoin(dateVo);

        list.stream().forEach(e -> {
            e.setDate(DateUtils.addDays(e.getDate(),-1));
            //MH/s 每秒转GH/s
            //e.setPv(e.getPv().divide(BigDecimal.valueOf(1000),scale,BigDecimal.ROUND_HALF_UP).stripTrailingZeros());
        });

        //最后一条用实时表最新一组数据  字段mhs24h对应实时24h算力
        HashRateDto lastDto = poolMapper.getPoolRealHashRateByCoin(vo);
        Date now = DateUtils.parseDate(DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD));
        lastDto.setDate(now);
        list.add(lastDto);
        watch.setList(list);
        watch.setUnit(unit.getUnit());
        return AjaxResult.success(watch);
    }
}
