package com.bonus.canteen.core.report.statistics.order.summary.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.bonus.canteen.core.auth.api.MgrAuthApi;
import com.bonus.canteen.core.auth.po.MgrUserAuthPO;
import com.bonus.canteen.core.common.enums.AllocMealtimeTypeEnum;
import com.bonus.canteen.core.common.page.PageVO;
import com.bonus.canteen.core.report.api.dto.ReportDeviceOrderSumDTO;
import com.bonus.canteen.core.report.api.vo.ReportOrderSumVO;
import com.bonus.canteen.core.report.statistics.constants.ReportSumTypeEnum;
import com.bonus.canteen.core.report.statistics.order.summary.mapper.ReportSumMachineMapper;
import com.bonus.canteen.core.report.statistics.order.summary.param.ReportMachineParam;
import com.bonus.canteen.core.report.statistics.order.summary.param.ReportMealtimeTypeCustNumDTO;
import com.bonus.canteen.core.report.statistics.order.summary.vo.ReportSumMachineMealTimeVO;
import com.bonus.canteen.core.report.statistics.order.summary.vo.ReportSumMachineVO;
import com.bonus.canteen.core.report.statistics.util.CommonConstants;
import com.bonus.canteen.core.report.vo.ReportBaseTotalVO;
import com.bonus.canteen.core.common.enums.SourceTypeEnum;
import com.github.pagehelper.page.PageMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class ReportSumMachineService {
   private static final Logger log = LoggerFactory.getLogger(ReportSumMachineService.class);
   @Autowired
   private ReportSumMachineMapper reportSumMachineMapper;
   @Autowired
   private MgrAuthApi mgrAuthApi;
   @Resource(
      name = "yunshitangTaskExecutor"
   )
   private AsyncTaskExecutor asyncTaskExecutor;

   public ReportBaseTotalVO<ReportSumMachineMealTimeVO> pageSummaryMealtime(ReportMachineParam param) {
      MgrUserAuthPO authPO = this.mgrAuthApi.getUserAuthPO();
      ReportMachineParam copyParam = (ReportMachineParam)BeanUtil.copyProperties(param, ReportMachineParam.class, new String[0]);
      CompletableFuture<List<ReportSumMachineMealTimeVO>> listFuture = CompletableFuture.supplyAsync(() -> {
         PageMethod.startPage(param.getPage());
         List<ReportSumMachineMealTimeVO> list = Objects.equals(param.getSumType(), ReportSumTypeEnum.PRE_TIME_DAY.key()) ?
                 this.reportSumMachineMapper.listSummaryMealtimeByDay(param, authPO) :
                 this.reportSumMachineMapper.listSummaryMealtime(param, authPO);
         List<String> collect = list.stream().map(ReportSumMachineMealTimeVO::getMachineSn).collect(Collectors.toList());
         copyParam.setMachineSnList(collect);
         if (param.getSumType().equals(CommonConstants.TWO)) {
            LocalDate minDate = (LocalDate)list.stream().map(ReportSumMachineMealTimeVO::getStatisticDate).min(LocalDate::compareTo).get();
            LocalDate maxDate = (LocalDate)list.stream().map(ReportSumMachineMealTimeVO::getStatisticDate).max(LocalDate::compareTo).get();
            copyParam.setStartDate(minDate);
            copyParam.setEndDate(maxDate);
         }

         List<ReportMealtimeTypeCustNumDTO> custNumList = this.reportSumMachineMapper.getDeviceMealtimeCustNum(copyParam, authPO);
         Map mapList;
         if (param.getSumType().equals(CommonConstants.TWO)) {
            mapList = (Map)custNumList.stream().collect(Collectors.groupingBy((o) -> {
               String var10000 = String.valueOf(o.getStatisticDate());
               return var10000 + "_" + o.getMachineSn();
            }));
         } else {
            mapList = (Map)custNumList.stream().collect(Collectors.groupingBy(ReportMealtimeTypeCustNumDTO::getMachineSn));
         }

         list.forEach((e) -> {
            String key;
            if (param.getSumType().equals(CommonConstants.TWO)) {
               String var10000 = String.valueOf(e.getStatisticDate());
               key = var10000 + "_" + e.getMachineSn();
            } else {
               key = e.getMachineSn();
            }

            List<ReportMealtimeTypeCustNumDTO> mealtimeTypeCustNumDTOS = (List)mapList.get(key);
            if (CollUtil.isNotEmpty(mealtimeTypeCustNumDTOS)) {
               Map<Integer, Integer> custNumMap = (Map)mealtimeTypeCustNumDTOS.stream().collect(Collectors.toMap(ReportMealtimeTypeCustNumDTO::getMealtimeType, ReportMealtimeTypeCustNumDTO::getCustNum));
               e.setBreakfastCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_BREAKFAST.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_BREAKFAST.getKey()));
               e.setLunchCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_LUNCH.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_LUNCH.getKey()));
               e.setAfternoonCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_AFTERNOON_TEA.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_AFTERNOON_TEA.getKey()));
               e.setDinnerCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_DINNER.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_DINNER.getKey()));
               e.setSupperCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_MIDNIGHT_SNACK.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_MIDNIGHT_SNACK.getKey()));
               e.setOtherCustNum(custNumMap.get(-1) == null ? 0 : (Integer)custNumMap.get(-1));
               e.setTotalCustNum(e.getBreakfastCustNum() + e.getLunchCustNum() + e.getAfternoonCustNum() + e.getDinnerCustNum() + e.getSupperCustNum() + e.getOtherCustNum());
            }

         });
         return list;
      }, this.asyncTaskExecutor);
      CompletableFuture<ReportSumMachineMealTimeVO> totalFuture = CompletableFuture.supplyAsync(() -> {
         ReportSumMachineMealTimeVO total = (ReportSumMachineMealTimeVO)Optional.ofNullable(this.reportSumMachineMapper.getSummaryMealtimeTotal(param, authPO)).orElse(new ReportSumMachineMealTimeVO());
         return total;
      }, this.asyncTaskExecutor);
      CompletableFuture<List<ReportMealtimeTypeCustNumDTO>> ListCustNumFuture = CompletableFuture.supplyAsync(() -> {
         param.setIfTotal(CommonConstants.ONE);
         List<ReportMealtimeTypeCustNumDTO> custNumList = this.reportSumMachineMapper.getDeviceMealtimeCustNum(param, authPO);
         return custNumList;
      }, this.asyncTaskExecutor);
      CompletableFuture<Void> future = CompletableFuture.allOf(listFuture, totalFuture, ListCustNumFuture);
      future.join();
      List<ReportSumMachineMealTimeVO> list = (List)listFuture.join();
      ReportSumMachineMealTimeVO total = totalFuture.join();
      List<ReportMealtimeTypeCustNumDTO> totalCustNumlist = ListCustNumFuture.join();
      Map<Integer, Integer> custNumMap = totalCustNumlist.stream().collect(Collectors.toMap(ReportMealtimeTypeCustNumDTO::getMealtimeType, ReportMealtimeTypeCustNumDTO::getCustNum));
      total.setBreakfastCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_BREAKFAST.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_BREAKFAST.getKey()));
      total.setLunchCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_LUNCH.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_LUNCH.getKey()));
      total.setAfternoonCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_AFTERNOON_TEA.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_AFTERNOON_TEA.getKey()));
      total.setDinnerCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_DINNER.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_DINNER.getKey()));
      total.setSupperCustNum(custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_MIDNIGHT_SNACK.getKey()) == null ? 0 : (Integer)custNumMap.get(AllocMealtimeTypeEnum.MEALTIME_MIDNIGHT_SNACK.getKey()));
      total.setOtherCustNum(custNumMap.get(-1) == null ? 0 : (Integer)custNumMap.get(-1));
      total.setTotalCustNum(total.getBreakfastCustNum() + total.getLunchCustNum() + total.getAfternoonCustNum() + total.getDinnerCustNum() + total.getSupperCustNum() + total.getOtherCustNum());
      return (new ReportBaseTotalVO()).setResultPage(PageVO.of(list)).setTotalLine(total);
   }

   private String formatSource(ReportSumMachineMealTimeVO payload) {
      List<String> source = new ArrayList();
      source.add(Objects.nonNull(payload.getConsumeSource()) ? payload.getConsumeSource() : null);
      source.add(Objects.nonNull(payload.getSourceType()) && !Objects.equals(payload.getSourceType(), -1) ? SourceTypeEnum.getDesc(payload.getSourceType()) : null);
      return (String)source.stream().filter(CharSequenceUtil::isNotBlank).collect(Collectors.joining("-"));
   }

   public ReportOrderSumVO getReportOrderSumForDevice(ReportDeviceOrderSumDTO param) {
      return this.reportSumMachineMapper.getReportOrderSumForDevice(param);
   }

   public ReportBaseTotalVO<ReportSumMachineVO> pageSummary(ReportMachineParam param) {
      MgrUserAuthPO authPO = this.mgrAuthApi.getUserAuthPO();
      CompletableFuture<List<ReportSumMachineVO>> listFuture = CompletableFuture.supplyAsync(() -> {
         ReportMachineParam copyParam = (ReportMachineParam)BeanUtil.copyProperties(param, ReportMachineParam.class, new String[0]);
         PageMethod.startPage(copyParam.getPage());
         List<ReportSumMachineVO> list = Objects.equals(param.getSumType(), ReportSumTypeEnum.PRE_TIME_DAY.key()) ? this.reportSumMachineMapper.listSummaryByDay(param, authPO) : this.reportSumMachineMapper.listSummary(param, authPO);
         list.forEach((e) -> {
            copyParam.setMachineName(e.getDeviceName());
            copyParam.setMachineNum(e.getDeviceNum());
            copyParam.setSourceType(e.getSourceType());
            copyParam.setStatisticDate(e.getStatisticDate());
            e.setCustNum(this.reportSumMachineMapper.getDeviceCustNum(copyParam, authPO));
            e.setConsumeSource(SourceTypeEnum.getDesc(e.getSourceType()));
         });
         return list;
      }, this.asyncTaskExecutor);
      CompletableFuture<ReportSumMachineVO> totalFuture = CompletableFuture.supplyAsync(() -> {
         ReportSumMachineVO total = (ReportSumMachineVO)Optional.ofNullable(this.reportSumMachineMapper.getSummaryTotal(param, authPO)).orElse(new ReportSumMachineVO());
         param.setIfTotal(CommonConstants.ONE);
         total.setCustNum(this.reportSumMachineMapper.getDeviceCustNum(param, authPO));
         return total;
      }, this.asyncTaskExecutor);
      CompletableFuture<Void> future = CompletableFuture.allOf(listFuture, totalFuture);
      future.join();
      List<ReportSumMachineVO> list = (List)listFuture.join();
      ReportSumMachineVO total = (ReportSumMachineVO)totalFuture.join();
      return (new ReportBaseTotalVO()).setResultPage(PageVO.of(list)).setTotalLine(total);
   }
}
