package com.qs.mp.quartz.task;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qs.mp.admin.domain.Ticket;
import com.qs.mp.admin.domain.TicketAwards;
import com.qs.mp.admin.domain.TicketBox;
import com.qs.mp.admin.service.ITicketAwardsService;
import com.qs.mp.admin.service.ITicketBoxService;
import com.qs.mp.admin.service.ITicketService;
import com.qs.mp.common.annotation.Log;
import com.qs.mp.common.core.domain.AjaxResult;
import com.qs.mp.common.enums.TicketTypeEnum;
import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
import com.qs.mp.common.utils.DateUtils;
import com.qs.mp.common.utils.LogUtil;
import com.qs.mp.common.utils.RSAUtil;
import com.qs.mp.user.domain.UserTicketOrder;
import com.qs.mp.user.service.IUserTicketOrderService;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

/**
 * 检查票组出奖率
 * @author zhongcp
 * @Date 2022/3/17
 */
@Component("ticketBoxTask")
public class TicketBoxTask {

  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());

  @Autowired
  private ITicketService ticketService;

  @Autowired
  private ITicketAwardsService ticketAwardsService;

  @Autowired
  private ITicketBoxService ticketBoxService;

  @Value("${export.page-size}")
  private int pageSize;

  /**
   * 检查票组中奖分布任务
   */
  public void checkPrize(String boxId) {
    LogUtil.info(logger, "...票组奖品分布检测任务开始..." + boxId);

    TicketBox ticketBox = ticketBoxService.getById(boxId);
    List<TicketAwards> ticketAwardsList = ticketAwardsService.list(new LambdaQueryWrapper<TicketAwards>().eq(TicketAwards::getBoxId, boxId));
    Map<String, TicketAwards> ticketAwardsMap = new HashMap<>();
    for (TicketAwards ticketAward : ticketAwardsList) {
      ticketAwardsMap.put(ticketAward.getName(), ticketAward);
    }

    List<Ticket> listAll = new ArrayList<Ticket>();
    // 首先查询要导出的数据总数
    LambdaQueryWrapper<Ticket> queryWrapper = new LambdaQueryWrapper<Ticket>();
    queryWrapper.eq(Ticket::getBoxId, boxId);
    int totalSize = ticketService.count(queryWrapper);
    if (totalSize == 0) {
      LogUtil.info(logger, "票组票数为0，boxId:{0}", boxId);
    }

    if(totalSize > pageSize) {
      int totalPage = totalSize%pageSize == 0 ? totalSize/pageSize : totalSize/pageSize+1;
      for (int i = 0; i < totalPage; i++) {
        LambdaQueryWrapper<Ticket> pageQueryWrapper = new LambdaQueryWrapper<Ticket>();
        pageQueryWrapper.select(Ticket::getSerialNo, Ticket::getDrawNum, Ticket::getCipherLuckyNum, Ticket::getPkgId);
        pageQueryWrapper.eq(Ticket::getBoxId, boxId);
        pageQueryWrapper.last("limit "+ (i*pageSize) +", " + pageSize);
        List<Ticket> list = ticketService.list(pageQueryWrapper);
        if(null != list && list.size() > 0 ) {
          listAll.addAll(list);
        }
      }
    }else {
      listAll = ticketService.list(queryWrapper);
    }

    HashMap<String, HashMap<String, Integer>> pkgAwardsMap = new HashMap<>();
    if(null != listAll && listAll.size() > 0 ) {
//      listAll.sort(Comparator.comparing(Ticket::getSerialNo));
      for (Ticket ticket : listAll) {
        LogUtil.info(logger, "ticketid:{0}", ticket.getTicketId());
        JSONArray jsonArray = JSONArray.parseArray(ticket.getDrawNum());
        for (int i = 0; i < jsonArray.size(); i++) {
          JSONObject jo = jsonArray.getJSONObject(i);
          String luckyNum = RSAUtil.decrypt(ticket.getCipherLuckyNum());
//          LogUtil.info(logger, "num:{0},luckyNum:{1}", new Object[]{jo.get("num"), luckyNum});
          if (jo.get("num") == Integer.valueOf(luckyNum)) {
            HashMap<String, Integer> awardsMap = pkgAwardsMap.get(ticket.getPkgId());
            if (awardsMap == null) {
              awardsMap = new HashMap<>();
              pkgAwardsMap.put(ticket.getPkgId(), awardsMap);
            }
            Integer awardsNum = awardsMap.get(jo.getString("name"));
            if (null == awardsNum) {
              awardsNum = 0;
            }
            awardsNum += 1;
            awardsMap.put(jo.getString("name"), awardsNum);
          }
        }
      }
    }
    LogUtil.info(logger, "票包奖品分布:{0}", JSONObject.toJSONString(pkgAwardsMap));
    // 奖级累计中奖数量
    Map<String, Integer> totalAwardsMap = new HashMap<>();
    for (String key : pkgAwardsMap.keySet()) {
      HashMap<String, Integer> awardsMap = pkgAwardsMap.get(key);

      int sumAwardsNum = 0;
      for (String subKey : awardsMap.keySet()) {
        sumAwardsNum += awardsMap.get(subKey);
        Integer totalAwardsNum = totalAwardsMap.get(subKey);
        if (totalAwardsNum == null) {
          totalAwardsNum = 0;
        }
        totalAwardsNum += awardsMap.get(subKey);
        totalAwardsMap.put(subKey, totalAwardsNum);
      }
      Assert.isTrue(sumAwardsNum == ticketBox.getPkgUnit(), "票包的中奖数和票包张数不匹配。总中奖数:" + sumAwardsNum + ",票包张数:" + ticketBox.getPkgUnit());
      // 检查票包每个奖项的中奖率是否和整体票组中奖率一致
      for (String subKey : awardsMap.keySet()) {
        BigDecimal hitRate = new BigDecimal(awardsMap.get(subKey) * 100).divide(new BigDecimal(sumAwardsNum), 4, RoundingMode.DOWN);
        // 误差率
        BigDecimal misRate = ticketAwardsMap.get(subKey).getHitRate().subtract(hitRate).divide(hitRate, 2, RoundingMode.HALF_UP);
        if (misRate.abs().compareTo(new BigDecimal(1)) > 0) {
          LogUtil.error(logger, "中奖率与整个票组的中奖率误差大于1，pkgId:{0},票包奖项:{1},数量:{2},票包中奖率:{3},票组中奖率:{4}",
              new Object[]{key, subKey, awardsMap.get(subKey), hitRate, ticketAwardsMap.get(subKey).getHitRate()});
        }
      }
      Map<String, Integer> treeMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
      treeMap.putAll(awardsMap);
      LogUtil.info(logger, "票包{0}奖级分布情况:{1}", new Object[]{key, treeMap});
    }
    // 排序
    Map<String, Integer> resultMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
    resultMap.putAll(totalAwardsMap);
    for (String key : resultMap.keySet()) {
      int realNum = resultMap.get(key);
      LogUtil.info(logger, "奖级{0}数量为{1}", new Object[]{key, realNum});
      if(realNum != ticketAwardsMap.get(key).getQuantity()) {
        LogUtil.error(logger, "实际中奖数(" + realNum + ")和票组中奖数(" + ticketAwardsMap.get(key).getQuantity() + ")不等" );
      }
    }
    LogUtil.info(logger, "...票组奖品分布检测任务结束...");
  }
}
