/*
 * Author: wangjian
 * 生成ServiceImpl
 */
package com.tofly.watermeter.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tofly.common.core.util.Date8Util;
import com.tofly.common.core.util.DateUtil;
import com.tofly.common.core.util.StringUtil;
import com.tofly.common.oauth.exception.ToflyDeniedException;
import com.tofly.common.oauth.util.SecurityUtils;
import com.tofly.watermeter.config.ComConstans;
import com.tofly.watermeter.config.ForeignConfig;
import com.tofly.watermeter.custom.dto.PageSheetDto;
import com.tofly.watermeter.custom.dto.PaymentInfoDto;
import com.tofly.watermeter.custom.dto.PaymentParamDto;
import com.tofly.watermeter.custom.dto.UserBalanceDto;
import com.tofly.watermeter.custom.entity.dto.SyncCommonDto;
import com.tofly.watermeter.custom.entity.dto.UpdateClientDto;
import com.tofly.watermeter.custom.entity.meterRead.AppRead;
import com.tofly.watermeter.custom.entity.meterRead.InitCbByHb;
import com.tofly.watermeter.custom.entity.meterRead.ReadSearch;
import com.tofly.watermeter.custom.entity.meterRead.readstatic.AuditMap;
import com.tofly.watermeter.custom.entity.meterRead.readstatic.ReadCollect;
import com.tofly.watermeter.custom.util.Date7Utils;
import com.tofly.watermeter.custom.util.SnowflakeUtils;
import com.tofly.watermeter.em.ApiCallEnum;
import com.tofly.watermeter.em.Constant;
import com.tofly.watermeter.em.ExcelExportFileTypeEnum;
import com.tofly.watermeter.entity.*;
import com.tofly.watermeter.mapper.QfcbplandetailsMapper;
import com.tofly.watermeter.mapper.QfkhjbxxMapper;
import com.tofly.watermeter.service.*;
import com.tofly.watermeter.util.JxlsUtils;
import com.tofly.watermeter.util.service.CallAPIService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 抄表计划详情表；
 *
 * @author wangjieliu
 * @date Fri Nov 05 00:00:00 CST 2021
 */
@Slf4j
@Service("qfcbplandetailsService")
public class QfcbplandetailsServiceImpl extends ServiceImpl<QfcbplandetailsMapper, Qfcbplandetails>
    implements QfcbplandetailsService {

  @Autowired private QfcbplanService qfcbplanService;
  @Autowired private QfcbqfmxService qfcbqfmxService;
  @Autowired private ReadmeterhisService readmeterhisService;
  @Autowired private QfcbqfmxlsService qfcbqfmxlsService;
  @Autowired private ForeignConfig foreignConfig;
  @Autowired private QfkhjbxxMapper qfkhjbxxMapper;
  @Autowired private QfkhjbxxService qfkhjbxxService;
  @Autowired private CallAPIService callApiService;
  @Autowired private QfcbplandetailsService qfcbplandetailsService;

  private static final Integer SHEET_SIZE = 10000;

  /** 下载时间 十点之前只能下载今天以前的 十点之后下载明天今天之前的 */
  @Value("${read.downtime}")
  private Integer downTime;

  @Override
  public List<Map> downloadUserInfo() {
    return qfkhjbxxMapper.getUserInfo(SecurityUtils.getUserId());
  }

  @Override
  public List<Map> getQyCollect(String isGeneral) {
    if (StringUtil.isEmpty(isGeneral)) {
      throw new ToflyDeniedException("请传递查询计划类型");
    }
    // 抄表人员ID
    Long cbry = SecurityUtils.getUserId();
    // 当前月
    String month = Date8Util.getYearMonth();
    // 今天或明天
    Integer day = DateUtil.getNowDay();
    day = calculateDay(isGeneral, day, month, cbry);
    List<Map> mapList = baseMapper.getQyCollect(isGeneral, cbry, month, day);
    for (Map map : mapList) {
      map.put("isGeneral", isGeneral);
      map.put("isQy", "1");
    }
    // 查询属于该抄表员的计划
    return mapList;
  }

  @Override
  public List<Map> qydPlanCollect(String isGeneral, String qybm) {
    if (StringUtil.isEmpty(isGeneral)) {
      throw new ToflyDeniedException("请传递查询计划类型");
    } else if (StringUtil.isEmpty(qybm)) {
      throw new ToflyDeniedException("请选择区域");
    }
    // 抄表人员ID
    Long cbry = SecurityUtils.getUserId();
    // 当前月
    String month = Date8Util.getYearMonth();
    // 今天或明天
    Integer day = DateUtil.getNowDay();
    day = calculateDay(isGeneral, day, month, cbry);
    List<Map> mapList = baseMapper.qydPlanCollect(isGeneral, cbry, month, qybm, day);
    for (Map map : mapList) {
      map.put("isGeneral", isGeneral);
      map.put("isQy", "0");
      map.put("cbqyBm", qybm);
    }
    return mapList;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public IPage<AppRead> appDwonData(Page page, String isGeneral,String type,String zone) {
    int year = Date8Util.getYear();
    if (!"1".equals(isGeneral) && !"0".equals(isGeneral)) {
      throw new ToflyDeniedException("请选择下载计划任务类型");
    }
    // 查找本年的年计划
    Qfcbplan qfcbplan =
        qfcbplanService.getOne(
            Wrappers.<Qfcbplan>lambdaQuery()
                .eq(Qfcbplan::getIsState, "1")
                .eq(Qfcbplan::getYear, year)
                .eq(Qfcbplan::getIsGeneral, isGeneral));
    if (StringUtil.isNotNull(qfcbplan)) {
      // 当前月
      String month = Date8Util.getYearMonth();
      // 抄表人员ID
      Long cbry = SecurityUtils.getUserId();
      // 下载今天或明天的计划
      Integer day = DateUtil.getNowDay();
      day = calculateDay(isGeneral, day, month, cbry);
      // 抄表数据
      IPage<AppRead> noCbDateList =
          qfcbqfmxService.getListByYhbh(page, day, month, isGeneral, cbry, qfcbplan.getId(),type,zone);
      if (StringUtil.isNotNull(noCbDateList) && noCbDateList.getRecords().size() > 0) {
        // 修改为下载状态；这里如果都已经抄表了，那肯定已经下载过了，所以不用考虑已经抄表状态的
        readmeterhisService.update(
            Wrappers.<Readmeterhis>lambdaUpdate()
                .in(
                    Readmeterhis::getSoleSign,
                    noCbDateList.getRecords().stream()
                        .map(AppRead::getSoleSign)
                        .collect(Collectors.toList()))
                .set(Readmeterhis::getXzbs, "1"));
        return noCbDateList;
      } else {
        long current = page.getCurrent();
        if (current == 1) {
          throw new ToflyDeniedException("暂无抄表数据");
        } else {
          throw new ToflyDeniedException("下载完成");
        }
      }
    } else {
      throw new ToflyDeniedException("本年度没有年计划");
    }
  }

  /**
   * 计算下载的开始日
   *
   * @param isGeneral 机械表卡表类型
   * @param day 开始日
   * @param month 月份
   * @return 允许下载的开始日
   */
  private Integer calculateDay(String isGeneral, Integer day, String month, Long cbry) {
    // 获取当前几点
    Integer nowHour = Integer.parseInt(DateUtil.parseDateToStr("HH", Date8Util.getCurrentDate()));
    if ("0".equals(isGeneral)) {
      // 并且已经抄完表的情况，在十点后才可以下载明天计划  必须将已下载的抄完
      int count =
          readmeterhisService.count(
              Wrappers.<Readmeterhis>lambdaQuery()
                  .eq(Readmeterhis::getCbry, cbry)
                  .le(Readmeterhis::getStartDay, day)
                  .eq(Readmeterhis::getIsGeneral, isGeneral)
                  .eq(Readmeterhis::getCbbz, "0")
                  .eq(Readmeterhis::getXzbs, "1")
                  .eq(Readmeterhis::getMonthPlan, month));
      // 判断是否十点之前，并且还有未抄数限制
      if (downTime > nowHour || count > 0) {
        // 十点之前只能展示今天以前的
        day = DateUtil.getNowDay();
      } else {
        // 十点之后展示明天今天之前的
        day =
            Integer.parseInt(
                DateUtil.parseDateToStr(
                    "dd",
                    Date7Utils.dateTimeDifference(
                        Date8Util.getCurrentDate(), 1, Calendar.DAY_OF_MONTH)));
      }
    } else {
      // 判断是否十点之前，如果是卡表则不加剩余没有抄完的限制
      if (downTime > nowHour) {
        // 十点之前只能展示今天以前的
        day = DateUtil.getNowDay();
      } else {
        // 十点之后展示明天今天之前的
        day =
            Integer.parseInt(
                DateUtil.parseDateToStr(
                    "dd",
                    Date7Utils.dateTimeDifference(
                        Date8Util.getCurrentDate(), 1, Calendar.DAY_OF_MONTH)));
      }
    }
    return day;
  }

  /**
   * 初始化抄表数据
   *
   * @return
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void initCbData() {
    int year = Date8Util.getYear();
    // 查找本年的年计划
    List<Qfcbplan> qfcbplanList =
        qfcbplanService.list(
            Wrappers.<Qfcbplan>lambdaQuery()
                .eq(Qfcbplan::getIsState, "1")
                .eq(Qfcbplan::getYear, year));
    Date currentDate = Date8Util.getCurrentDate();
    // 当月
    int month = Integer.parseInt(DateUtil.parseDateToStr("MM", currentDate));
    // 月计划月份
    String monthPlan = DateUtil.parseDateToStr("yyyyMM", currentDate);
    // 首先判断是双月（0）还是单月（1）
    String sinAndDou = month % 2 == 0 ? "0" : "1";
    // 可能存在两种情况：卡表和机械表任务
    for (Qfcbplan qfcbplan : qfcbplanList) {
      if (StringUtil.isNotNull(qfcbplan)) {
        Long planId = qfcbplan.getId();
        // 查询制定好的子计划详情
        List<Qfcbplandetails> qfcbplandetailsList =
            this.list(
                Wrappers.<Qfcbplandetails>lambdaQuery()
                    .eq(Qfcbplandetails::getPlanId, planId)
                    .eq(Qfcbplandetails::getIsState, "1")
                    .isNotNull(Qfcbplandetails::getCbry)
                    .isNotNull(Qfcbplandetails::getSinDouMonth)
                    .isNotNull(Qfcbplandetails::getStartDay)
                    .isNotNull(Qfcbplandetails::getEndDay)
                    // 筛选数据 符合单月/双月/每月抄表
                    .and(
                        v ->
                            v.eq(Qfcbplandetails::getSinDouMonth, sinAndDou)
                                .or()
                                .eq(Qfcbplandetails::getSinDouMonth, "2"))
                    .select(
                        Qfcbplandetails::getCbqyBm,
                        Qfcbplandetails::getCbqydBm,
                        Qfcbplandetails::getSinDouMonth,
                        Qfcbplandetails::getStartDay,
                        Qfcbplandetails::getEndDay,
                        Qfcbplandetails::getIsGeneral,
                        Qfcbplandetails::getSinDouMonth,
                        Qfcbplandetails::getCbqyMc,
                        Qfcbplandetails::getCbry,
                        Qfcbplandetails::getQydmc));
        if (StringUtil.isNotNull(qfcbplandetailsList) && qfcbplandetailsList.size() > 0) {
          //抄表生成优化
          //获取区段列表
          Map<String, List<Qfcbplandetails>> zoneGroup = qfcbplandetailsList.stream().filter(q -> "0".equals(q.getIsGeneral()))
                  .collect(Collectors.groupingBy(Qfcbplandetails::getCbqyBm));
          List<Readmeterhis> saveBatchList = new ArrayList<>();
          for (String zone : zoneGroup.keySet()) {
            List<String> sectionList = zoneGroup.get(zone).stream().filter(q -> "0".equals(q.getIsGeneral()))
                    .map(Qfcbplandetails::getCbqydBm)
                    .collect(Collectors.toList());

            log.info("开始生成" + zone + "区域抄表数据");
            //暂时只生成人工抄表数据,已生成的用户数据不会再次生成
            List<Readmeterhis> initCbDataList = readmeterhisService.getInitCbDataList(sectionList, "0");

            if (CollectionUtils.isNotEmpty(initCbDataList)){
              //根据区域段分组
              Map<String, List<Readmeterhis>> groupData = initCbDataList.stream().collect(Collectors.groupingBy(Readmeterhis::getCbqydBm));
              for (Qfcbplandetails qfcbplandetail : qfcbplandetailsList) {
                String startPlanTime = monthPlan + qfcbplandetail.getStartDay() + " 00:00:00";
                String endPlanTime = monthPlan + qfcbplandetail.getEndDay() + " 23:59:59";
                Date startDate = DateUtil.formatDate(startPlanTime, "yyyyMMdd HH:mm:ss");
                Date endDate = DateUtil.formatDate(endPlanTime, "yyyyMMdd HH:mm:ss");
                String isGeneral = qfcbplandetail.getIsGeneral();
                // 查找区域段下的用户
                String qydbm = qfcbplandetail.getCbqydBm();
                List<Readmeterhis> readmeterhisList = groupData.get(qydbm);
                if (CollectionUtils.isNotEmpty(readmeterhisList)){
                  readmeterhisList.forEach(
                          k -> {
                            // 唯一标识
                            k.setSoleSign(
                                    SnowflakeUtils.getId(
                                            foreignConfig.getDate(),
                                            foreignConfig.getWorkerId(),
                                            ComConstans.SNOWFLAKE_READ_TYPE)
                                            .toString());
                            k.setCbbz("0");
                            k.setChildSort(0);
                            k.setCbry(qfcbplandetail.getCbry());
                            k.setCbryName(qfcbplandetail.getCbryName());
                            k.setStartRq(startDate);
                            k.setEndRq(endDate);
                            k.setPlanId(planId);
                            k.setXzbs("0");
                            k.setIsGeneral(isGeneral);
                            k.setSinDouMonth(qfcbplandetail.getSinDouMonth());
                            k.setStartDay(qfcbplandetail.getStartDay());
                            k.setEndDay(qfcbplandetail.getEndDay());
                            k.setCbqyMc(qfcbplandetail.getCbqyMc());
                            k.setCbqyBm(qfcbplandetail.getCbqyBm());
                            k.setCbqydBm(qfcbplandetail.getCbqydBm());
                            k.setQydmc(qfcbplandetail.getQydmc());
                            k.setMonthPlan(monthPlan);
                          });
                  log.info("生成抄表数据" + readmeterhisList.size() + "条");
                  saveBatchList.addAll(readmeterhisList);
                }
              }
            }
          }
          readmeterhisService.saveBatch(saveBatchList,1000);
          log.info("生成抄表数据完毕,共添加抄表数据：" + saveBatchList.size() + "条");
          // 循环本年区域段 ，只在每月28日凌晨执行一次(由于区域段太多循环查询效率过慢)
          /*for (Qfcbplandetails qfcbplandetail : qfcbplandetailsList) {
            // 拼接开始日和结束日
            String startPlanTime = monthPlan + qfcbplandetail.getStartDay() + " 00:00:00";
            String endPlanTime = monthPlan + qfcbplandetail.getEndDay() + " 23:59:59";
            Date startDate = DateUtil.formatDate(startPlanTime, "yyyyMMdd HH:mm:ss");
            Date endDate = DateUtil.formatDate(endPlanTime, "yyyyMMdd HH:mm:ss");
            String isGeneral = qfcbplandetail.getIsGeneral();
            // 查找区域段下的用户
            String qydbm = qfcbplandetail.getCbqydBm();
            List<Readmeterhis> readmeterhisList;
            log.info("区域段编码：" + qydbm + "开始生成数据");
            if ("0".equals(isGeneral)) {
              // 销户的用户不制定计划
              readmeterhisList = readmeterhisService.getInitCbData(qydbm, isGeneral);
            } else {
              // 销户的用户不制定计划
              readmeterhisList = readmeterhisService.getInitCbDataCard(qydbm);
            }
            if (!readmeterhisList.isEmpty()) {
              readmeterhisList.forEach(
                  k -> {
                    // 唯一标识
                    k.setSoleSign(
                        SnowflakeUtils.getId(
                                foreignConfig.getDate(),
                                foreignConfig.getWorkerId(),
                                ComConstans.SNOWFLAKE_READ_TYPE)
                            .toString());
                    k.setCbbz("0");
                    k.setChildSort(0);
                    k.setCbry(qfcbplandetail.getCbry());
                    k.setCbryName(qfcbplandetail.getCbryName());
                    k.setStartRq(startDate);
                    k.setEndRq(endDate);
                    k.setPlanId(planId);
                    k.setXzbs("0");
                    k.setIsGeneral(isGeneral);
                    k.setSinDouMonth(qfcbplandetail.getSinDouMonth());
                    k.setStartDay(qfcbplandetail.getStartDay());
                    k.setEndDay(qfcbplandetail.getEndDay());
                    k.setCbqyMc(qfcbplandetail.getCbqyMc());
                    k.setCbqyBm(qfcbplandetail.getCbqyBm());
                    k.setCbqydBm(qfcbplandetail.getCbqydBm());
                    k.setQydmc(qfcbplandetail.getQydmc());
                    k.setMonthPlan(monthPlan);
                  });
              //                    boolean flag =
              // yhbingqyService.insertShouldCbYh(readmeterhisList, qfcbplandetail, monthPlan);
              readmeterhisService.saveBatch(readmeterhisList);
              log.info("区域段编码：" + qydbm + "已生成" + readmeterhisList.size() + "条数据");
            }
          }*/
        }
      }
    }
    //查询是否存在重复数据
    List<Integer> repeat = baseMapper.countRepeatReadMater();
    if (CollectionUtils.isNotEmpty(repeat)){
      baseMapper.deleteRepeatData();
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean initData() {
    int year = Date8Util.getYear();
    // 查找本年的年计划
    List<Qfcbplan> qfcbplanList =
        qfcbplanService.list(
            Wrappers.<Qfcbplan>lambdaQuery()
                .eq(Qfcbplan::getIsState, "1")
                .eq(Qfcbplan::getYear, year));
    Date currentDate = Date8Util.getCurrentDate();
    // 当月
    int month = Integer.parseInt(DateUtil.parseDateToStr("MM", currentDate));
    // 月计划月份
    String monthPlan = DateUtil.parseDateToStr("yyyyMM", currentDate);
    // 首先判断是双月（0）还是单月（1）
    String sinAndDou = month % 2 == 0 ? "0" : "1";
    // 可能存在两种情况：卡表和机械表任务
    for (Qfcbplan qfcbplan : qfcbplanList) {
      if (StringUtil.isNotNull(qfcbplan)) {
        Long planId = qfcbplan.getId();
        // 查询制定好的子计划详情
        List<Qfcbplandetails> qfcbplandetailsList =
            this.list(
                Wrappers.<Qfcbplandetails>lambdaQuery()
                    .eq(Qfcbplandetails::getPlanId, planId)
                    .eq(Qfcbplandetails::getIsState, "1")
                    .isNotNull(Qfcbplandetails::getCbry)
                    .isNotNull(Qfcbplandetails::getSinDouMonth)
                    .isNotNull(Qfcbplandetails::getStartDay)
                    .isNotNull(Qfcbplandetails::getEndDay)
                    // 筛选数据 符合单月/双月/每月抄表
                    .and(
                        v ->
                            v.eq(Qfcbplandetails::getSinDouMonth, sinAndDou)
                                .or()
                                .eq(Qfcbplandetails::getSinDouMonth, "2"))
                    .select(
                        Qfcbplandetails::getCbqyBm,
                        Qfcbplandetails::getCbqydBm,
                        Qfcbplandetails::getSinDouMonth,
                        Qfcbplandetails::getStartDay,
                        Qfcbplandetails::getEndDay,
                        Qfcbplandetails::getIsGeneral,
                        Qfcbplandetails::getSinDouMonth,
                        Qfcbplandetails::getCbqyMc,
                        Qfcbplandetails::getCbry,
                        Qfcbplandetails::getQydmc));
        if (StringUtil.isNotNull(qfcbplandetailsList) && qfcbplandetailsList.size() > 0) {
          Map<String, List<Qfcbplandetails>> zoneGroup = qfcbplandetailsList.stream().filter(q -> "0".equals(q.getIsGeneral()))
                  .collect(Collectors.groupingBy(Qfcbplandetails::getCbqyBm));
          List<Readmeterhis> saveBatchList = new ArrayList<>();
          for (String zone : zoneGroup.keySet()) {
            List<String> sectionList = zoneGroup.get(zone).stream().filter(q -> "0".equals(q.getIsGeneral()))
                    .map(Qfcbplandetails::getCbqydBm)
                    .collect(Collectors.toList());

            log.info("开始生成" + zone + "区域抄表数据");
            //暂时只生成人工抄表数据
            List<Readmeterhis> initCbDataList = readmeterhisService.getInitCbDataList(sectionList, "0");

            if (CollectionUtils.isNotEmpty(initCbDataList)){
              //根据区域段分组
              Map<String, List<Readmeterhis>> groupData = initCbDataList.stream().collect(Collectors.groupingBy(Readmeterhis::getCbqydBm));
              for (Qfcbplandetails qfcbplandetail : qfcbplandetailsList) {
                String startPlanTime = monthPlan + qfcbplandetail.getStartDay() + " 00:00:00";
                String endPlanTime = monthPlan + qfcbplandetail.getEndDay() + " 23:59:59";
                Date startDate = DateUtil.formatDate(startPlanTime, "yyyyMMdd HH:mm:ss");
                Date endDate = DateUtil.formatDate(endPlanTime, "yyyyMMdd HH:mm:ss");
                String isGeneral = qfcbplandetail.getIsGeneral();
                // 查找区域段下的用户
                String qydbm = qfcbplandetail.getCbqydBm();
                List<Readmeterhis> readmeterhisList = groupData.get(qydbm);
                if (CollectionUtils.isNotEmpty(readmeterhisList)){
                  readmeterhisList.forEach(k -> {
                            // 唯一标识
                            k.setSoleSign(
                                    SnowflakeUtils.getId(
                                            foreignConfig.getDate(),
                                            foreignConfig.getWorkerId(),
                                            ComConstans.SNOWFLAKE_READ_TYPE)
                                            .toString());
                            k.setCbbz("0");
                            k.setChildSort(0);
                            k.setCbry(qfcbplandetail.getCbry());
                            k.setCbryName(qfcbplandetail.getCbryName());
                            k.setStartRq(startDate);
                            k.setEndRq(endDate);
                            k.setPlanId(planId);
                            k.setXzbs("0");
                            k.setIsGeneral(isGeneral);
                            k.setSinDouMonth(qfcbplandetail.getSinDouMonth());
                            k.setStartDay(qfcbplandetail.getStartDay());
                            k.setEndDay(qfcbplandetail.getEndDay());
                            k.setCbqyMc(qfcbplandetail.getCbqyMc());
                            k.setCbqyBm(qfcbplandetail.getCbqyBm());
                            k.setCbqydBm(qfcbplandetail.getCbqydBm());
                            k.setQydmc(qfcbplandetail.getQydmc());
                            k.setMonthPlan(monthPlan);
                          });
                  log.info("生成抄表数据" + readmeterhisList.size() + "条");
                  saveBatchList.addAll(readmeterhisList);
                }
              }
            }
          }
          readmeterhisService.saveBatch(saveBatchList,1000);
          log.info("生成抄表数据完毕,共添加抄表数据：" + saveBatchList.size() + "条");
          // 循环本年区域段 ，只在每月28日凌晨执行一次
          /*for (Qfcbplandetails qfcbplandetail : qfcbplandetailsList) {
            // 当前月份已生成计划的区段
            List<String> qdList =
                qfkhjbxxMapper.getCbqdBm(monthPlan, qfcbplandetail.getIsGeneral());
            // 拼接开始日和结束日
            String startPlanTime = monthPlan + qfcbplandetail.getStartDay() + " 00:00:00";
            String endPlanTime = monthPlan + qfcbplandetail.getEndDay() + " 23:59:59";
            Date startDate = DateUtil.formatDate(startPlanTime, "yyyyMMdd HH:mm:ss");
            Date endDate = DateUtil.formatDate(endPlanTime, "yyyyMMdd HH:mm:ss");
            String isGeneral = qfcbplandetail.getIsGeneral();
            // 查找区域段下的用户
            String qydbm = qfcbplandetail.getCbqydBm();
            // 当该区段存在跳过
            if (qdList.contains(qydbm)) {
              continue;
            }
            List<Readmeterhis> readmeterhisList;
            log.info("区域段编码：" + qydbm + "开始生成数据");
            if ("0".equals(isGeneral)) {
              // 销户的用户不制定计划
              readmeterhisList = readmeterhisService.getInitCbData(qydbm, isGeneral);
            } else {
              // 销户的用户不制定计划
              readmeterhisList = readmeterhisService.getInitCbDataCard(qydbm);
            }
            if (!readmeterhisList.isEmpty()) {
              readmeterhisList.forEach(
                  k -> {
                    // 唯一标识
                    k.setSoleSign(
                        SnowflakeUtils.getId(
                                foreignConfig.getDate(),
                                foreignConfig.getWorkerId(),
                                ComConstans.SNOWFLAKE_READ_TYPE)
                            .toString());
                    k.setCbbz("0");
                    k.setChildSort(0);
                    k.setCbry(qfcbplandetail.getCbry());
                    k.setCbryName(qfcbplandetail.getCbryName());
                    k.setStartRq(startDate);
                    k.setEndRq(endDate);
                    k.setPlanId(planId);
                    k.setXzbs("0");
                    k.setIsGeneral(isGeneral);
                    k.setSinDouMonth(qfcbplandetail.getSinDouMonth());
                    k.setStartDay(qfcbplandetail.getStartDay());
                    k.setEndDay(qfcbplandetail.getEndDay());
                    k.setCbqyMc(qfcbplandetail.getCbqyMc());
                    k.setCbqyBm(qfcbplandetail.getCbqyBm());
                    k.setCbqydBm(qfcbplandetail.getCbqydBm());
                    k.setQydmc(qfcbplandetail.getQydmc());
                    k.setMonthPlan(monthPlan);
                  });
              //                    boolean flag =
              // yhbingqyService.insertShouldCbYh(readmeterhisList, qfcbplandetail, monthPlan);
              readmeterhisService.saveBatch(readmeterhisList);
              log.info("区域段编码：" + qydbm + "已生成" + readmeterhisList.size() + "条数据");
            }
          }*/
        }
      }
    }
    //查询是否存在重复数据
    List<Integer> repeat = baseMapper.countRepeatReadMater();
    if (CollectionUtils.isNotEmpty(repeat)){
      baseMapper.deleteRepeatData();
    }
    return true;
  }

  @Override
  public void initCbslEveyDay() {
    String yearMonth = Date8Util.getYearMonth();
    // 查找当月未抄表的数据
    baseMapper.initCbslEveyDay(yearMonth);
  }

  @Override
  public AppRead queryOfflineByYhbh(String cbrq, String yhbh) {
    return qfcbqfmxService.queryOfflineByYhbh(cbrq, yhbh);
  }

  /**
   * 通过客户编号获取抄表数据
   *
   * @param page page
   * @param client 客户编号
   * @param startDate 开始日期
   * @param endDate 结束日期
   * @return page
   */
  @Override
  public Page getClientMeterReading(Page page, String client, String startDate, String endDate) {
    return baseMapper.getClientMeterReading(page, client, startDate, endDate);
  }

  /**
   * 获取用户余额
   *
   * @param clientCode 用户编号
   * @return list
   */
  @Override
  public List<UserBalanceDto> getUserBalance(String clientCode) {
    Map<String, Object> map = new HashMap<>();
    map.put("accountCode", clientCode);
    Map apiResult = callApiService.getApiResult(map, "/api/v1/koi/hall/index/account/get");
    List<UserBalanceDto> result = null;
    if (CollectionUtils.isNotEmpty(apiResult)) {
      String data = String.valueOf(apiResult.get("data"));
      if (StringUtils.isNotBlank(data)) {
        result = JSONObject.parseArray(data, UserBalanceDto.class);
      }
    }
    return result;
  }

  /**
   * 获取缴费信息
   *
   * @param page page
   * @param client 客户编号
   * @return page
   */
  @Override
  public Page getPaymentInfo(Page page, String client, Integer type) {

    if (StringUtils.isBlank(client)) {
      throw new ToflyDeniedException("用户编号不允许为空");
    }
    // 默认缴费模板id，1 扣费模板id
    String id =
        type == null
            ? "965942259331728384"
            : type == 0 ? "965942259331728384" : "996798424319788032";

    PaymentInfoDto paymentInfo = new PaymentInfoDto();
    paymentInfo.setId(id);
    paymentInfo.setExportType(1);
    paymentInfo.setNeedSummary(0);
    paymentInfo.setPageNum(page.getCurrent());
    paymentInfo.setPageSize(page.getSize());
    paymentInfo.setQueryName("按账户");
    List<PaymentParamDto> parameters = new ArrayList<>();
    parameters.add(new PaymentParamDto("ACCOUNT_CODE", client));
    paymentInfo.setParameters(parameters);

    Map apiResult = callApiService.getApiResult(paymentInfo, "/api/v1/seagull/query/execute");

    if (CollectionUtil.isNotEmpty(apiResult)) {
      if (ApiCallEnum.STATUS_CODE_OK
          .getCode()
          .equals(String.valueOf(apiResult.get("statusCode")))) {
        String data = String.valueOf(apiResult.get("data"));
        if (StringUtils.isNotBlank(data)) {
          Map dataMap = JSONObject.parseObject(data, Map.class);
          if (CollectionUtils.isNotEmpty(dataMap)) {
            String resultData = String.valueOf(dataMap.get("resultData"));
            if (StringUtils.isNotBlank(resultData)) {
              Map resultDataMap = JSONObject.parseObject(resultData, Map.class);
              if (CollectionUtils.isNotEmpty(resultDataMap)) {
                int total = Integer.parseInt(String.valueOf(resultDataMap.get("total")));
                page.setTotal(total);
                if (total > 0) {
                  String list = String.valueOf(resultDataMap.get("list"));
                  List<Map> dataList = JSONObject.parseArray(list, Map.class);
                  page.setRecords(dataList);
                }
              }
            }
          }
        }
      }
    } else {
      throw new ToflyDeniedException(String.valueOf(apiResult.get("message")));
    }

    return page;
  }

  /**
   * 修改用户手机号
   *
   * @return boolean
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean updateUserPhone(UpdateClientDto dto) {
    String phone = dto.getPhone();
    String clientCode = dto.getClientCode();
    String meterCode = dto.getMeterCode();
    String waterAddress = dto.getWaterAddress();
    String vendorCode = dto.getVendorCode();
    String vendorName = dto.getVendorName();
    if (StringUtils.isBlank(clientCode)) {
      throw new ToflyDeniedException("用户编号不允许为空");
    }
    //修改用户电话
    if (StringUtils.isNotBlank(phone)){
      Map<String, Object> queryClient = new HashMap<>();
      queryClient.put("code", clientCode);
      //首先查询用户信息
      Map clientResult = callApiService.getApiResult(queryClient, "/api/v1/koi/customer/change/get");
      if (CollectionUtil.isNotEmpty(clientResult)) {
        if (ApiCallEnum.STATUS_CODE_OK.getCode().equals(String.valueOf(clientResult.get("statusCode")))) {
          Map clientMap = JSONObject.parseObject(String.valueOf(clientResult.get("data")), Map.class);

          if (CollectionUtils.isNotEmpty(clientMap)){
            clientMap.put("contactPhone",phone);

            Map<String,Object> updateMap = new HashMap<>();
            updateMap.put("id",clientMap.get("id"));
            updateMap.put("typeCode","1");
            updateMap.put("personal",clientMap);
            Map updateResult = callApiService.getApiResult(updateMap, "/api/v1/koi/customer/change/update");
            if (ApiCallEnum.STATUS_CODE_OK.getCode().equals(String.valueOf(updateResult.get("statusCode")))){
              //修改已同步用户数据
              qfkhjbxxService.update(Wrappers.<Qfkhjbxx>lambdaUpdate().set(Qfkhjbxx::getLxdh,phone).eq(Qfkhjbxx::getYhbh,clientCode));
            }else {
              throw new ToflyDeniedException(String.valueOf(updateResult.get("message")));
            }
          }else {
            throw new ToflyDeniedException("未在营销查询到该客户");
          }
        }else {
          throw new ToflyDeniedException(String.valueOf(clientResult.get("message")));
        }
      }
    }
    //修改水表地址、厂家、编号
    if (StringUtils.isNotBlank(waterAddress) || StringUtils.isNotBlank(meterCode) || StringUtils.isNotBlank(vendorCode)){
      Map<String, Object> queryClient = new HashMap<>();
      queryClient.put("userCode", clientCode);
      //首先查询用户信息
      Map clientResult = callApiService.getApiResult(queryClient, "/api/v1/koi/user/meter/information/get");
      if (CollectionUtil.isNotEmpty(clientResult)) {
        if (ApiCallEnum.STATUS_CODE_OK.getCode().equals(String.valueOf(clientResult.get("statusCode")))) {
          Map clientMap = JSONObject.parseObject(String.valueOf(clientResult.get("data")), Map.class);

          if (CollectionUtils.isNotEmpty(clientMap)){
            if (StringUtils.isNotBlank(waterAddress)){
              clientMap.put("meterLocation",waterAddress);
            }
            if (StringUtils.isNotBlank(meterCode)){
              clientMap.put("meterCode",meterCode);
            }
            if (StringUtils.isNotBlank(vendorCode)){
              clientMap.put("vendorCode",vendorCode);
              clientMap.put("vendorName",vendorName);
            }
            Map updateResult = callApiService.getApiResult(clientMap, "/api/v1/koi/user/meter/information/update");
            if (ApiCallEnum.STATUS_CODE_OK.getCode().equals(String.valueOf(updateResult.get("statusCode")))){
              //修改已同步用户数据
              qfkhjbxxService.update(Wrappers.<Qfkhjbxx>lambdaUpdate()
                      .set(StringUtils.isNotBlank(meterCode),Qfkhjbxx::getSbbh,meterCode)
                      .set(StringUtils.isNotBlank(vendorCode),Qfkhjbxx::getSbcj,vendorCode)
                      .set(StringUtils.isNotBlank(waterAddress),Qfkhjbxx::getSbwz,waterAddress)
                      .eq(Qfkhjbxx::getYhbh,clientCode));
            }else {
              throw new ToflyDeniedException(String.valueOf(updateResult.get("message")));
            }
          }else {
            throw new ToflyDeniedException("未在营销查询到该客户");
          }
        }
      }
    }
    return true;
  }

  /**
   * 获取水表厂家线下
   *
   * @return list
   */
  @Override
  public List<Map> getVendorInfo() {
    List<Map> result = new ArrayList<>();
    Map apiResult =
        callApiService.getApiResult(new SyncCommonDto(1, 200), "/api/Business/WaterMaker");
    if (ApiCallEnum.STATUS_CODE_OK.getCode().equals(String.valueOf(apiResult.get("statusCode")))) {
      result = JSONObject.parseArray(String.valueOf(apiResult.get("data")), Map.class);
    }
    return result;
  }


  /**
   * 获取用户基本信息
   *
   * @param clientCode 用户编号
   * @return list
   */
  @Override
  public Map getBasicInformation(String clientCode) {
    if (StringUtils.isBlank(clientCode)){
      throw new ToflyDeniedException("用户编号不允许为空");
    }
    Map<String, Object> params = new HashMap<>();
    params.put("code",clientCode);
    Map apiResult = callApiService.getApiResult(params, "/api/v1/koi/user/information/base");
    Map result = new HashMap();
    if (ApiCallEnum.STATUS_CODE_OK.getCode().equals(String.valueOf(apiResult.get("statusCode")))){
      result =  JSONObject.parseObject(String.valueOf(apiResult.get("data")), Map.class);
    }
    return result;
  }

  /**
   * 获取用户账单
   *
   * @param page
   * @param clientCode 用户编号
   * @return page
   */
  @Override
  public Page getBillInfo(Page page, String clientCode,Integer type) {
    if (StringUtils.isBlank(clientCode)){
      throw new ToflyDeniedException("用户编号不允许为空");
    }
    if (type == null){
      throw new ToflyDeniedException("查询类型不允许为空");
    }
    Map<String, Object> params = new HashMap<>();
    params.put("code",clientCode);
    params.put("pageNum", page.getCurrent());
    params.put("pageSize",page.getSize());
    String url;
    switch(type) {
      //欠费记录
      case 1:
        url = "/api/v1/koi/user/information/unpaid/bill/find/page";
        break;
      //资金流水
      case 2:
        url = "/api/v1/koi/user/information/charge/find/page";
        break;
      //用户账单
      case 0:
      default:
        url = "/api/v1/koi/user/information/bill/find/page";
        break;
    }
    Map apiResult = callApiService.getApiResult(params, url);
    if (ApiCallEnum.STATUS_CODE_OK.getCode().equals(String.valueOf(apiResult.get("statusCode")))){
      Map dataMap =  JSONObject.parseObject(String.valueOf(apiResult.get("data")), Map.class);
      if (CollectionUtils.isNotEmpty(dataMap)){
        long total = Long.parseLong(String.valueOf(dataMap.get("total")));
        if (total > 0){
          page.setTotal(total);
          page.setRecords(JSONObject.parseArray(String.valueOf(dataMap.get("list")), Map.class));
        }
      }
    }
    return page;
  }

  /**
   * 获取账单总和
   *
   * @return map
   */
  @Override
  public Map getBillTotal(String code,Integer type) {
    Map result = new HashMap();
    int t = type == null ? 1 : type;
    Map<String,Object> params = new HashMap(1);
    params.put("code", code);
    String url;
    switch(t) {
      case 0:
        url = "/api/v1/koi/user/information/bill/count";
        break;
      case 2:
        url = "/api/v1/koi/user/information/charge/count";
        break;
      case 1:
      default:
        url = "/api/v1/koi/user/information/unpaid/bill/count";
        break;
    }
    Map apiResult = callApiService.getApiResult(params, url);
    if (ApiCallEnum.STATUS_CODE_OK.getCode().equals(String.valueOf(apiResult.get("statusCode")))){
      result = JSONObject.parseObject(String.valueOf(apiResult.get("data")), Map.class);
    }
    return result;
  }

  /**
   * 获取当前用户区域
   *
   * @return list
   */
  @Override
  public List<Map> getUserZone(String isGeneral) {
    return baseMapper.getUserZone(SecurityUtils.getUserId(),isGeneral);
  }


  @Override
  @Transactional(rollbackFor = Exception.class)
  public void initCbDataByMonth(Integer month, String monthPlan) {
    if (StringUtil.isNull(month) && StringUtil.isEmpty(monthPlan)) {
      throw new ToflyDeniedException("传递年月份和月");
    }

    int year = Date8Util.getYear();
    // 查找本年的年计划
    Qfcbplan qfcbplan =
        qfcbplanService.getOne(
            Wrappers.<Qfcbplan>lambdaQuery()
                .eq(Qfcbplan::getIsState, "1")
                .eq(Qfcbplan::getYear, year));
    if (StringUtil.isNotNull(qfcbplan)) {
      Long planId = qfcbplan.getId();
      // 下个月
      //            int month = Integer.parseInt(DateUtil.parseDateToStr("MM",
      // Date7Utils.addNextPeriod(1, Date8Util.getCurrentDate())));
      // 首先判断是双月（0）还是单月（1）
      String sinAndDou = month % 2 == 0 ? "0" : "1";
      // 查询制定好的计划
      List<Qfcbplandetails> qfcbplandetailsList =
          this.list(
              Wrappers.<Qfcbplandetails>lambdaQuery()
                  .eq(Qfcbplandetails::getPlanId, planId)
                  .eq(Qfcbplandetails::getIsState, "1")
                  .isNotNull(Qfcbplandetails::getCbry)
                  .isNotNull(Qfcbplandetails::getSinDouMonth)
                  .isNotNull(Qfcbplandetails::getStartDay)
                  .isNotNull(Qfcbplandetails::getEndDay)
                  // 筛选数据 符合单月/双月/每月抄表
                  .and(
                      v ->
                          v.eq(Qfcbplandetails::getSinDouMonth, sinAndDou)
                              .or()
                              .eq(Qfcbplandetails::getSinDouMonth, "2"))
                  .select(
                      Qfcbplandetails::getCbqyBm,
                      Qfcbplandetails::getCbqydBm,
                      Qfcbplandetails::getSinDouMonth,
                      Qfcbplandetails::getStartDay,
                      Qfcbplandetails::getEndDay,
                      Qfcbplandetails::getIsGeneral,
                      Qfcbplandetails::getSinDouMonth,
                      Qfcbplandetails::getCbqyMc,
                      Qfcbplandetails::getCbry,
                      Qfcbplandetails::getQydmc));
      if (StringUtil.isNotNull(qfcbplandetailsList) && qfcbplandetailsList.size() > 0) {
        // 月计划月份：下一个月的
        //                String monthPlan = DateUtil.parseDateToStr("yyyyMM",
        // Date7Utils.addNextPeriod(1, Date8Util.getCurrentDate()));
        // 循环本年区域段 ，只在每月28日凌晨执行一次，所以对数据库的压力不大(就在那一会亚历山大)
        for (Qfcbplandetails qfcbplandetail : qfcbplandetailsList) {
          // 拼接开始日和结束日
          String startPlanTime = monthPlan + qfcbplandetail.getStartDay() + " 00:00:00";
          String endPlanTime = monthPlan + qfcbplandetail.getEndDay() + " 23:59:59";
          Date startDate = DateUtil.formatDate(startPlanTime, "yyyyMMdd HH:mm:ss");
          Date endDate = DateUtil.formatDate(endPlanTime, "yyyyMMdd HH:mm:ss");
          // 查找区域段下的用户
          String qydbm = qfcbplandetail.getCbqydBm();
          List<Readmeterhis> readmeterhisList =
              readmeterhisService.getInitCbData(qydbm, qfcbplandetail.getIsGeneral());
          readmeterhisList.forEach(
              k -> {
                k.setCbbz("0");
                k.setCbry(qfcbplandetail.getCbry());
                k.setCbryName(qfcbplandetail.getCbryName());
                k.setStartRq(startDate);
                k.setEndRq(endDate);
                k.setPlanId(planId);
                k.setXzbs("0");
                k.setIsGeneral(qfcbplandetail.getIsGeneral());
                k.setSinDouMonth(qfcbplandetail.getSinDouMonth());
                k.setStartDay(qfcbplandetail.getStartDay());
                k.setEndDay(qfcbplandetail.getEndDay());
                k.setCbqyMc(qfcbplandetail.getCbqyMc());
                k.setCbqyBm(qfcbplandetail.getCbqyBm());
                k.setCbqydBm(qfcbplandetail.getCbqydBm());
                k.setQydmc(qfcbplandetail.getQydmc());
                k.setMonthPlan(monthPlan);
              });
          readmeterhisService.saveBatch(readmeterhisList);
        }
      }
    }
  }

  @Override
  public void initCbDataByHbByMonth(String monthPlan) {
    if (StringUtil.isEmpty(monthPlan)) {
      throw new ToflyDeniedException("必传年月份");
    }
    // 月计划月份：下一个月的
    //        String monthPlan = DateUtil.parseDateToStr("yyyyMM", Date7Utils.addNextPeriod(1,
    // Date8Util.getCurrentDate()));
    // 获取换表日期大于上次抄表日期的最新换表信息（新表起度，旧表止读，换表类型）
    List<InitCbByHb> hbInfo = readmeterhisService.initCbDataByHb(monthPlan);
    if (StringUtil.isNotNull(hbInfo) && hbInfo.size() > 0) {
      // 将换表信息（换表类型、旧表止读、新表起度）保存到下月计划对应的用户中，需要添加字段；还需要创建（monthPlan字段）索引，避免数据过大造成卡顿
      // 还有定时器的制定，定时器时间在上面的初始化抄表月计划后
      readmeterhisService.initCbPlanHb(hbInfo, monthPlan);
    }
  }

  @Override
  public void initFrontThreeDataByMonth(String monthPlan) {
    if (StringUtil.isEmpty(monthPlan)) {
      throw new ToflyDeniedException("必传年月份");
    }
    // 月计划月份：下一个月的
    //        String monthPlan = DateUtil.parseDateToStr("yyyyMM", Date7Utils.addNextPeriod(1,
    // Date8Util.getCurrentDate()));
    // 先获取数目
    int count = readmeterhisService.getInitFrontThreeDataCount(monthPlan);
    if (count > 0) {
      int size = (int) Math.ceil(Double.valueOf(count) / 100d);
      for (int i = 0; i < size; i++) {
        Page page = new Page();
        page.setCurrent(i + 1);
        page.setSize(100);
        // 前三次水量和抄表日期，目前普查表抄表不能从森鑫炬获取，所以只有is_general = 0 （人工机械抄表） 的计划才能从森鑫炬抄表历史数据中获取前三次抄表数据
        List<Readmeterhis> readmeterhisList =
            readmeterhisService.getInitFrontThreeData(page, monthPlan);
        if (StringUtil.isNotNull(readmeterhisList) && readmeterhisList.size() > 0) {
          // 初始化前三次抄表水量、抄表日期、上次读数
          readmeterhisService.initFrontThreeData(readmeterhisList, monthPlan);
        }
      }
    }
  }

  @Override
  public void initFrontThreeData() {
    // 月计划月份：下一个月的
    String monthPlan =
        DateUtil.parseDateToStr("yyyyMM", Date7Utils.addNextPeriod(1, Date8Util.getCurrentDate()));
    // 先获取数目
    int count = readmeterhisService.getInitFrontThreeDataCount(monthPlan);
    if (count > 0) {
      int size = (int) Math.ceil(Double.valueOf(count) / 100d);
      for (int i = 0; i < size; i++) {
        Page page = new Page();
        page.setCurrent(i + 1);
        page.setSize(100);
        // 前三次水量和抄表日期，目前普查表抄表不能从森鑫炬获取，所以只有is_general = 0 （人工机械抄表） 的计划才能从森鑫炬抄表历史数据中获取前三次抄表数据
        List<Readmeterhis> readmeterhisList =
            readmeterhisService.getInitFrontThreeData(page, monthPlan);
        if (StringUtil.isNotNull(readmeterhisList) && readmeterhisList.size() > 0) {
          // 初始化前三次抄表水量、抄表日期、上次读数
          readmeterhisService.initFrontThreeData(readmeterhisList, monthPlan);
        }
      }
    }
  }

  /** 这里可以使用SQL优化。不用代码去查询修改，利用update与select的结合修改前三年水量数据 */
  @Override
  public void initFrontThreeYearData() {
    // 当月
    Date nextYearMonth = Date8Util.getCurrentDate();
    String monthPlan = DateUtil.parseDateToStr("yyyyMM", nextYearMonth);
    // 一年前
    Date tm1 =
        cn.hutool.core.date.DateUtil.beginOfMonth(Date7Utils.addNextPeriod(-12, nextYearMonth));
    String toStr1 = DateUtil.parseDateToStr("yyyyMM", tm1);
    // 两年前
    Date tm2 =
        cn.hutool.core.date.DateUtil.beginOfMonth(Date7Utils.addNextPeriod(-24, nextYearMonth));
    String toStr2 = DateUtil.parseDateToStr("yyyyMM", tm2);
    // 三年前
    Date tm3 =
        cn.hutool.core.date.DateUtil.beginOfMonth(Date7Utils.addNextPeriod(-36, nextYearMonth));
    String toStr3 = DateUtil.parseDateToStr("yyyyMM", tm3);
    // 需要区分机械表和卡表
    List<String> cardOrGen = new ArrayList<>();
    cardOrGen.add("0");
    cardOrGen.add("1");
    for (String isGeneral : cardOrGen) {
      int count =
          readmeterhisService.count(
              Wrappers.<Readmeterhis>lambdaQuery()
                  .eq(Readmeterhis::getMonthPlan, monthPlan)
                  .eq(Readmeterhis::getIsGeneral, isGeneral));
      if (count > 0) {
        int size = (int) Math.ceil(Double.valueOf(count) / 200d);
        for (int i = 0; i < size; i++) {
          Page page = new Page();
          page.setCurrent(i + 1);
          page.setSize(200);
          IPage<Readmeterhis> readmeterhisIPage =
              readmeterhisService.page(
                  page,
                  Wrappers.<Readmeterhis>lambdaQuery()
                      .eq(Readmeterhis::getIsGeneral, isGeneral)
                      .eq(Readmeterhis::getMonthPlan, monthPlan)
                      .select(Readmeterhis::getYhbh));
          List<String> yhbhList =
              readmeterhisIPage.getRecords().stream()
                  .map(Readmeterhis::getYhbh)
                  .collect(Collectors.toList());
          if (StringUtil.isNotNull(yhbhList) && yhbhList.size() > 0) {
            // 查询一年前历史抄表水量数据
            List qfcbqfmxl1 = null;
            // 查询一年前历史抄表水量数据
            List qfcbqfmxl2 = null;
            // 查询一年前历史抄表水量数据
            List qfcbqfmxl3 = null;
            if ("0".equals(isGeneral)) {
              qfcbqfmxl1 =
                  qfcbqfmxlsService.list(
                      Wrappers.<Qfcbqfmxls>lambdaQuery()
                          .in(Qfcbqfmxls::getYhbh, yhbhList)
                          .eq(Qfcbqfmxls::getMonthTime, tm1)
                          .select(Qfcbqfmxls::getYhbh, Qfcbqfmxls::getCbsl));

              qfcbqfmxl1 =
                  qfcbqfmxlsService.list(
                      Wrappers.<Qfcbqfmxls>lambdaQuery()
                          .in(Qfcbqfmxls::getYhbh, yhbhList)
                          .eq(Qfcbqfmxls::getMonthTime, tm2)
                          .select(Qfcbqfmxls::getYhbh, Qfcbqfmxls::getCbsl));

              qfcbqfmxl1 =
                  qfcbqfmxlsService.list(
                      Wrappers.<Qfcbqfmxls>lambdaQuery()
                          .in(Qfcbqfmxls::getYhbh, yhbhList)
                          .eq(Qfcbqfmxls::getMonthTime, tm3)
                          .select(Qfcbqfmxls::getYhbh, Qfcbqfmxls::getCbsl));
            } else {
              qfcbqfmxl1 =
                  readmeterhisService.list(
                      Wrappers.<Readmeterhis>lambdaQuery()
                          .in(Readmeterhis::getYhbh, yhbhList)
                          .eq(Readmeterhis::getMonthPlan, tm1)
                          .select(Readmeterhis::getYhbh, Readmeterhis::getCbsl));
              qfcbqfmxl1 =
                  readmeterhisService.list(
                      Wrappers.<Readmeterhis>lambdaQuery()
                          .in(Readmeterhis::getYhbh, yhbhList)
                          .eq(Readmeterhis::getMonthPlan, tm2)
                          .select(Readmeterhis::getYhbh, Readmeterhis::getCbsl));
              qfcbqfmxl1 =
                  readmeterhisService.list(
                      Wrappers.<Readmeterhis>lambdaQuery()
                          .in(Readmeterhis::getYhbh, yhbhList)
                          .eq(Readmeterhis::getMonthPlan, tm3)
                          .select(Readmeterhis::getYhbh, Readmeterhis::getCbsl));
            }
            // 修改抄表水量数据
            if (qfcbqfmxl1.size() > 0) {
              readmeterhisService.updateYearCbsl1(qfcbqfmxl1, monthPlan, toStr1);
            }
            if (qfcbqfmxl2.size() > 0) {
              readmeterhisService.updateYearCbsl2(qfcbqfmxl2, monthPlan, toStr2);
            }
            if (qfcbqfmxl3.size() > 0) {
              readmeterhisService.updateYearCbsl3(qfcbqfmxl3, monthPlan, toStr3);
            }
          }
        }
      }
    }
  }

  @Override
  public void initFrontThreeYearDataByMonth(String monthPlan) {
    //        DateUtil.formatDate(monthPlan , "yyyyMM");
    Date nextYearMonth = DateUtil.formatDate(monthPlan, "yyyyMM");
    //        String monthPlan = DateUtil.parseDateToStr("yyyyMM", nextYearMonth);
    // 一年前
    Date tm1 =
        cn.hutool.core.date.DateUtil.beginOfMonth(Date7Utils.addNextPeriod(-12, nextYearMonth));
    String toStr1 = DateUtil.parseDateToStr("yyyyMM", tm1);
    // 两年前
    Date tm2 =
        cn.hutool.core.date.DateUtil.beginOfMonth(Date7Utils.addNextPeriod(-24, nextYearMonth));
    String toStr2 = DateUtil.parseDateToStr("yyyyMM", tm2);
    // 三年前
    Date tm3 =
        cn.hutool.core.date.DateUtil.beginOfMonth(Date7Utils.addNextPeriod(-36, nextYearMonth));
    String toStr3 = DateUtil.parseDateToStr("yyyyMM", tm3);
    int count =
        readmeterhisService.count(
            Wrappers.<Readmeterhis>lambdaQuery().eq(Readmeterhis::getMonthPlan, monthPlan));
    if (count > 0) {
      int size = (int) Math.ceil(Double.valueOf(count) / 200d);
      for (int i = 0; i < size; i++) {
        Page page = new Page();
        page.setCurrent(i + 1);
        page.setSize(200);
        IPage<Readmeterhis> readmeterhisIPage =
            readmeterhisService.page(
                page,
                Wrappers.<Readmeterhis>lambdaQuery()
                    .eq(Readmeterhis::getMonthPlan, monthPlan)
                    .select(Readmeterhis::getYhbh));
        List<String> yhbhList =
            readmeterhisIPage.getRecords().stream()
                .map(Readmeterhis::getYhbh)
                .collect(Collectors.toList());
        if (StringUtil.isNotNull(yhbhList) && yhbhList.size() > 0) {
          // 查询一年前历史抄表水量数据
          List<Qfcbqfmxls> qfcbqfmxl1 =
              qfcbqfmxlsService.list(
                  Wrappers.<Qfcbqfmxls>lambdaQuery()
                      .in(Qfcbqfmxls::getYhbh, yhbhList)
                      .eq(Qfcbqfmxls::getMonthTime, tm1)
                      .select(Qfcbqfmxls::getYhbh, Qfcbqfmxls::getCbsl));
          // 查询一年前历史抄表水量数据
          List<Qfcbqfmxls> qfcbqfmxl2 =
              qfcbqfmxlsService.list(
                  Wrappers.<Qfcbqfmxls>lambdaQuery()
                      .in(Qfcbqfmxls::getYhbh, yhbhList)
                      .eq(Qfcbqfmxls::getMonthTime, tm2)
                      .select(Qfcbqfmxls::getYhbh, Qfcbqfmxls::getCbsl));
          // 查询一年前历史抄表水量数据
          List<Qfcbqfmxls> qfcbqfmxl3 =
              qfcbqfmxlsService.list(
                  Wrappers.<Qfcbqfmxls>lambdaQuery()
                      .in(Qfcbqfmxls::getYhbh, yhbhList)
                      .eq(Qfcbqfmxls::getMonthTime, tm3)
                      .select(Qfcbqfmxls::getYhbh, Qfcbqfmxls::getCbsl));
          // 修改抄表水量数据
          if (qfcbqfmxl1.size() > 0) {
            readmeterhisService.updateYearCbsl1(qfcbqfmxl1, monthPlan, toStr1);
          }
          if (qfcbqfmxl2.size() > 0) {
            readmeterhisService.updateYearCbsl2(qfcbqfmxl2, monthPlan, toStr2);
          }
          if (qfcbqfmxl3.size() > 0) {
            readmeterhisService.updateYearCbsl3(qfcbqfmxl3, monthPlan, toStr3);
          }
        }
      }
    }
  }

  @Override
  public void initCbDataByHb() {
    // 月计划月份：下一个月的
    //        String monthPlan = DateUtil.parseDateToStr("yyyyMM", Date7Utils.addNextPeriod(1,
    // Date8Util.getCurrentDate()));
    // 当月
    String monthPlan = DateUtil.parseDateToStr("yyyyMM", Date8Util.getCurrentDate());
    // 获取换表日期大于上次抄表日期的最新换表信息（新表起度，旧表止读，换表类型）
    List<InitCbByHb> hbInfo = readmeterhisService.initCbDataByHb(monthPlan);
    if (StringUtil.isNotNull(hbInfo) && hbInfo.size() > 0) {
      // 将换表信息（换表类型、旧表止读、新表起度）保存到下月计划对应的用户中，需要添加字段；还需要创建（monthPlan字段）索引，避免数据过大造成卡顿
      // 还有定时器的制定，定时器时间在上面的初始化抄表月计划后
      readmeterhisService.initCbPlanHb(hbInfo, monthPlan);
    }
  }

  @Override
  public List<ReadCollect> getOffline(String yearMonth, String cbry, String qybm, String qydbm, String isGeneral, HttpServletResponse respons, String template) {
    if (StringUtil.isEmpty(yearMonth)) {
      throw new ToflyDeniedException("请选择月份");
    } else if (StringUtil.isEmpty(isGeneral)) {
      throw new ToflyDeniedException("请传递类型");
    }
    List<String> cbryList = null;
    List<String> qybmList = null;
    List<String> qydbmList = null;

    if (StringUtil.isNotEmpty(cbry)) {
      cbryList = Arrays.asList(cbry.split(","));
    }
    if (StringUtil.isNotEmpty(qybm)) {
      qybmList = Arrays.asList(qybm.split(","));
    }
    if (StringUtil.isNotEmpty(qydbm)) {
      qydbmList = Arrays.asList(qydbm.split(","));
    }
    //        List<Readmeterhis> readmeterhisList =
    // readmeterhisService.list(Wrappers.<Readmeterhis>lambdaQuery()
    //                .eq(Readmeterhis::getMonthPlan, yearMonth)
    //                .eq(Readmeterhis::getIsGeneral, isGeneral)
    //                .in(StringUtil.isNotNull(cbryList), Readmeterhis::getCbry, cbryList)
    //                .in(StringUtil.isNotNull(qybmList), Readmeterhis::getCbqyBm, qybmList)
    //                .in(StringUtil.isNotNull(qydbmList), Readmeterhis::getCbqydBm, qydbmList)
    //                .and(v -> v.eq(Readmeterhis::getCbbz, "0").or().eq(Readmeterhis::getCbbz,
    // "1"))
    //                .orderByAsc(Readmeterhis::getCbqyMc, Readmeterhis::getQydmc)
    //                .select(Readmeterhis::getCbry, Readmeterhis::getCbqyBm,
    //                        Readmeterhis::getCbqyMc, Readmeterhis::getCbqydBm,
    //                        Readmeterhis::getShbz, Readmeterhis::getCbryName,
    //                        Readmeterhis::getCbbz, Readmeterhis::getQydmc));

    // 汇总数据查询优化，之前代码处理  效率太低了
    List<ReadCollect> offlineList =
        readmeterhisService.getOffline(yearMonth, isGeneral, cbryList, qybmList, qydbmList);
    Map<String, List<ReadCollect>> groupByQyMap =
        offlineList.stream().collect(Collectors.groupingBy(ReadCollect::getCbqybm));
    for (ReadCollect readCollect : offlineList) {
      String cbqybm = readCollect.getCbqybm();
      List<ReadCollect> qydInfoList = groupByQyMap.get(cbqybm);
      Integer qyNum = 0;
      for (ReadCollect collect : qydInfoList) {
        qyNum = qyNum + collect.getAllNum();
      }
      readCollect.setQyNum(qyNum);
    }
    return offlineList;
    //        //对抄表人员分组
    //        Map<String, List<Readmeterhis>> groupByCbryMap =
    // readmeterhisList.stream().collect(Collectors.groupingBy(cbrymcid -> cbrymcid.getCbryName() +
    // "-" + cbrymcid.getCbry()));
    //        List<ReadCollect> resultMapList = new ArrayList<>();
    //        //遍历抄表人员分组后的数据
    //        groupByCbryMap.forEach((k, v) -> {
    //            ReadCollect cbryMap = new ReadCollect();
    //            List<ReadCollect> qyList = new ArrayList<>();
    //            //抄表人员分组后，对区域分组数据
    //            Map<String, List<Readmeterhis>> groupByQyMap =
    // v.stream().collect(Collectors.groupingBy(qymcbm -> qymcbm.getCbqyMc() + "-" +
    // qymcbm.getCbqyBm()));
    //            String[] cbryInfo = k.split("-");
    //            cbryMap.setCbry(cbryInfo[0]);
    //            cbryMap.setCbryId(Long.parseLong(cbryInfo[1]));
    //            //计算区域异常总数
    //            groupByQyMap.forEach((kk, vv) -> {
    //                ReadCollect qyMap = new ReadCollect();
    //                String[] cbqyInfo = kk.split("-");
    //                qyMap.setCbqy(cbqyInfo[0]);
    //                qyMap.setCbqybm(cbqyInfo[1]);
    //                qyMap.setQyNum(vv.size());
    //                //区域分组后，对区域段分组
    //                Map<String, List<Readmeterhis>> groupByQydMap =
    // vv.stream().collect(Collectors.groupingBy(qydmcbm -> qydmcbm.getQydmc() + "-" +
    // qydmcbm.getCbqydBm()));
    //                List<ReadCollect> qydList = new ArrayList<>();
    //                groupByQydMap.forEach((kkk, vvv) -> {
    //                    ReadCollect qydMap = new ReadCollect();
    //                    String[] qydInfo = kkk.split("-");
    //                    qydMap.setCbqyd(qydInfo[0]);
    //                    qydMap.setCbqydbm(qydInfo[1]);
    //                    Map<String, List<Readmeterhis>> cbbzMap =
    // vvv.stream().collect(Collectors.groupingBy(Readmeterhis::getCbbz));
    //                    if (StringUtil.isNotNull(cbbzMap.get("0"))) {
    //                        qydMap.setNoCbNum(cbbzMap.get("0").size());
    //                    } else {
    //                        qydMap.setNoCbNum(0);
    //                    }
    //                    if (StringUtil.isNotNull(cbbzMap.get("1"))) {
    //                        qydMap.setCbNum(cbbzMap.get("1").size());
    //                    } else {
    //                        qydMap.setCbNum(0);
    //                    }
    //                    qydMap.setAllNum(vvv.size());
    //                    qydList.add(qydMap);
    //                });
    //                qydList.sort(Comparator.comparing(ReadCollect::getCbqyd));
    //                //存放区域下的区域段集合
    //                qyMap.setList(qydList);
    //                qyList.add(qyMap);
    //            });
    //            //存放抄表人员下的区域集合
    //            cbryMap.setList(qyList);
    //            resultMapList.add(cbryMap);
    //        });
    //        if ("1".equals(template)) {
    //            //处理数据，合并行参数
    //            for (ReadCollect readCollect : resultMapList) {
    //                int cell = 0;
    //                //拿到最大合并行数
    //                for (ReadCollect collect : readCollect.getList()) {
    //                    cell = cell + collect.getList().size();
    //                }
    //                readCollect.setRow(cell);
    //            }
    //            // 根据templateServiceType,templateFlag获取对应模板数据，找到枚举中相应的Excel文件名、路径等信息
    //            ExcelExportFileTypeEnum excelExportFileTypeEnum =
    //                    ExcelExportFileTypeEnum.getExcelExportFileTypeEnum("readCollect",
    // template);
    //            if (null == excelExportFileTypeEnum) {
    //                return null;
    //            }
    //            Map<String, Object> model = new HashMap<>(10);
    //            model.put("dataMap", resultMapList);
    //            JxlsUtils.exportExcel(excelExportFileTypeEnum, model, respons,
    // Constant.FILE_PATH_TEST_EXPORT_EXCEL);
    //            return null;
    //        } else {
    //            return resultMapList;
    //        }

  }

  @Override
  public IPage<AuditMap> getOfflineInfo(Page page, ReadSearch search, HttpServletResponse response) {
    // 抄表业务这一块，太多的查询其实大部分上是一致了的，但是前期没有想到，导致冗余SQL太多了；我日，我自己也太TM垃圾了吧
    String sspq = search.getSspq();
    String cbb = search.getCbb();
    String cbry = search.getCbryName();
    String cwyf = search.getCwyf();
    String isDis = search.getIsDis();
    String isGeneral = search.getIsGeneral();
    String template = search.getTemplateFlag();
    String state = search.getState();
    String issyn = search.getIssyn();
    String isEstimate = search.getIsEstimate();
    String cbfs = search.getCbfs();
    String inputContent = search.getInputContent();
    String isUpdate = search.getIsUpdate();
    if (StringUtil.isEmpty(cwyf)) {
      throw new ToflyDeniedException("选择时间月份");
    } else if (StringUtil.isEmpty(isGeneral)) {
      throw new ToflyDeniedException("请选择计划类型");
    }
    List<String> qybmList = null;
    List<String> qydbmList = null;
    List<String> cbryList = null;
    List<String> cbfsList = null;
    if (StringUtil.isNotEmpty(sspq)) {
      qybmList = Arrays.asList(sspq.split(","));
    }
    if (StringUtil.isNotEmpty(cbb)) {
      qydbmList = Arrays.asList(cbb.split(","));
    }
    if (StringUtil.isNotEmpty(cbry)) {
      cbryList = Arrays.asList(cbry.split(","));
    }
    if (StringUtil.isNotEmpty(cbfs)) {
      cbfsList = Arrays.asList(cbfs.split(","));
    }
    if ("1".equals(template)) {
      //            List<AuditMap> list1 = qfcbqfmxService.getOfflineInfoList(cwyf, qybmList,
      // qydbmList, cbryList, isDis, isGeneral, state, isEstimate, issyn, cbfsList, inputContent,
      // isUpdate);
      List<Map> list =
          qfkhjbxxMapper.getOfflineInfoList(
              cwyf,
              qybmList,
              qydbmList,
              cbryList,
              isDis,
              isGeneral,
              state,
              isEstimate,
              issyn,
              cbfsList,
              inputContent,
              isUpdate);
      List<PageSheetDto> dto = this.pageSheetDate(list);
      // 根据templateServiceType,templateFlag获取对应模板数据，找到枚举中相应的Excel文件名、路径等信息
      ExcelExportFileTypeEnum excelExportFileTypeEnum;
      if ("0".equals(isGeneral)) {
        // 机械表
        excelExportFileTypeEnum =
            ExcelExportFileTypeEnum.getExcelExportFileTypeEnum("offlineInfo", "1");
      } else {
        // 卡表
        excelExportFileTypeEnum =
            ExcelExportFileTypeEnum.getExcelExportFileTypeEnum("offlineInfo", "2");
      }
      if (null == excelExportFileTypeEnum) {
        return null;
      }
      Map<String, Object> model = new HashMap<>(10);
      model.put("dataMaps", dto);
      model.put(
          "sheetNames", dto.stream().map(PageSheetDto::getSheetName).collect(Collectors.toList()));
      JxlsUtils.exportExcel(
          excelExportFileTypeEnum, model, response, Constant.FILE_PATH_TEST_EXPORT_EXCEL);
      return null;
    } else {
      IPage<AuditMap> iPage =
          qfcbqfmxService.getOfflineInfo(
              page,
              cwyf,
              qybmList,
              qydbmList,
              cbryList,
              isDis,
              isGeneral,
              state,
              isEstimate,
              issyn,
              cbfsList,
              inputContent,
              isUpdate);
      return iPage;
    }
  }

  @Override
  public AppRead getOfflineByYhbh(
      String yearMonth, String yhbh, String isGeneral, Long cbryId, String soleSign) {
    //        if (StringUtil.isEmpty(yearMonth)) {
    //            throw new ToflyDeniedException("请选择月份");
    //        } else if (StringUtil.isEmpty(isGeneral)) {
    //            throw new ToflyDeniedException("请传递类型");
    //        } else if (StringUtil.isEmpty(yhbh)) {
    //            throw new ToflyDeniedException("请传递用户编号");
    //        } else if (StringUtil.isNull(cbryId)) {
    //            throw new ToflyDeniedException("请传递抄表人员");
    //        }
    return qfcbqfmxService.getOfflineByYhbh(yearMonth, yhbh, isGeneral, cbryId, soleSign);
  }

  @Override
  public void savePlanBatch(List<Qfcbplandetails> detailsList) {
    baseMapper.savePlanBatch(detailsList);
  }

  @Override
  public void savePlanCbryBatch(List<Qfcbplandetails> detailsList) {
    baseMapper.savePlanCbryBatch(detailsList);
  }

  @Override
  public Map appCollect(String isGeneral, String yearMonth) {
    isGeneral = "1".equals(isGeneral) ? "1" : "0";
    if (StringUtil.isEmpty(yearMonth)) {
      throw new ToflyDeniedException("请选择年月查询");
    }
    // 抄表人员
    Long cbry = SecurityUtils.getUserId();
    // 抄表百分比
    Map percentMap = baseMapper.appCollect(isGeneral, yearMonth, cbry);
    // 区域段未完成个数
    Map qydMap = baseMapper.getQydCbInfo(isGeneral, yearMonth, cbry);
    if (StringUtil.isNull(qydMap)) {
      percentMap.put("noFinishQYD", 0);
    } else {
      percentMap.put("noFinishQYD", qydMap.get("nofinishqyd"));
    }
    // 区域未完成个数
    Map qyMap = baseMapper.qyCbInfo(isGeneral, yearMonth, cbry);
    if (StringUtil.isNull(qyMap)) {
      percentMap.put("qyNoFinishNum", 0);
    } else {
      percentMap.put("qyNoFinishNum", qyMap.get("nofinishqy"));
    }
    percentMap.put(
        "finishQYD",
        Integer.parseInt(percentMap.get("qydnum").toString())
            - Integer.parseInt(percentMap.get("noFinishQYD").toString()));
    percentMap.put(
        "qyFinishNum",
        Integer.parseInt(percentMap.get("qynum").toString())
            - Integer.parseInt(percentMap.get("qyNoFinishNum").toString()));
    return percentMap;
  }

  private List<PageSheetDto> pageSheetDate(List<Map> list) {
    List<PageSheetDto> result = new ArrayList<>();
    if (list != null && list.size() > 0) {
      int size = list.size();
      int number = (int) Math.ceil((float) size / SHEET_SIZE);
      // 截取下标范围
      int startIndex;
      int endIndex;
      PageSheetDto dto;
      for (int i = 1; i <= number; i++) {
        dto = new PageSheetDto();
        startIndex = (i - 1) * SHEET_SIZE;
        if (i == number) {
          endIndex = size;
        } else {
          endIndex = i * SHEET_SIZE;
        }
        dto.setCurrent(i + "");
        dto.setTotal(size + "");
        dto.setSheetName("sheet" + i);
        dto.setData(list.subList(startIndex, endIndex));
        result.add(dto);
      }
    }
    return result;
  }
}
