package com.bonus.canteen.core.cook.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.bonus.canteen.core.common.utils.SpringContextHolder;
import com.bonus.canteen.core.cook.domain.CookDishes;
import com.bonus.canteen.core.cook.domain.CookRecipeDetail;
import com.bonus.canteen.core.cook.domain.CookRecipeDishes;
import com.bonus.canteen.core.cook.dto.ImportRecipeDishesDTO;
import com.bonus.canteen.core.cook.mapper.CookDishesMapper;
import com.bonus.canteen.core.cook.mapper.CookRecipeDetailMapper;
import com.bonus.canteen.core.cook.mapper.CookRecipeDishesMapper;
import com.bonus.common.core.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class CookRecipeImportListener extends AnalysisEventListener<Map<Integer, String>> {
   private static final Logger log = LoggerFactory.getLogger(CookRecipeImportListener.class);
   private final String sheetName;
   private final Long recipeId;
   private final Long mealtimeType;
   private final Map<Integer, LocalDate> dateMap = new HashMap();
   private final Set<String> dishesNames = new HashSet();
   private final Set<String> notImportDishesNames = new HashSet();
   private final Map<LocalDate, List<ImportRecipeDishesDTO>> datas = new HashMap();
   private final BigDecimal decimal = new BigDecimal(100);

   public Set<String> getNotImportDishesNames() {
      return this.notImportDishesNames;
   }

   public CookRecipeImportListener(String sheetName, Long recipeId, Long mealtimeType) {
      this.sheetName = sheetName;
      this.recipeId = recipeId;
      this.mealtimeType = mealtimeType;
   }

   @Override
   public void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {
      Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
      String no;
      if (rowIndex == 1) {
         no = (String)integerStringMap.get(1);
         log.info("餐次名称：{}", no);
      }

      if (rowIndex == 2) {
         for(int i = 1; i < integerStringMap.size(); i += 3) {
            String date = (String)integerStringMap.get(i);
            if (date != null && !date.isEmpty()) {
               Date parse = DateUtil.parse(date);
               String format = DateUtil.format(parse, "yyyy/MM/dd");
               String[] split = format.split("/");
               LocalDate localDate = LocalDate.of(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
               this.dateMap.put(i, localDate);
            }
         }

         log.info("导入的日期：{}", this.dateMap.values());
      }

      if (rowIndex > 2) {
         try {
            no = (String)integerStringMap.get(0);
            if (no != null && !no.isEmpty()) {
               for(int i = 1; i < integerStringMap.size(); i += 3) {
                  String dishesName = (String)integerStringMap.get(i);
                  if (!ObjectUtil.isEmpty(dishesName)) {
                     ImportRecipeDishesDTO importRecipeDishesDto = new ImportRecipeDishesDTO();
                     this.dishesNames.add(dishesName);
                     BigDecimal price = (new BigDecimal((String)integerStringMap.get(i + 1))).multiply(this.decimal);
                     BigDecimal salePrice = (new BigDecimal((String)integerStringMap.get(i + 2))).multiply(this.decimal);
                     importRecipeDishesDto.setSurplusNum(9999).setIndex(i).setDishesName(dishesName).setSaleNum(0).setSupplyNum(9999).setRestrictNum(9999).setPrice(price.intValue()).setSalePrice(salePrice.intValue());
                     if (this.datas.containsKey(this.dateMap.get(i))) {
                        ((List)this.datas.get(this.dateMap.get(i))).add(importRecipeDishesDto);
                     } else {
                        List<ImportRecipeDishesDTO> list = new ArrayList();
                        list.add(importRecipeDishesDto);
                        this.datas.put((LocalDate)this.dateMap.get(i), list);
                     }
                  }
               }
            }
         } catch (Exception var11) {
            log.info("解析excel失败：DATA:{}", integerStringMap);
         }
      }

   }


   @Override
   public void doAfterAllAnalysed(AnalysisContext analysisContext) {
       try {
           HashSet<LocalDate> dates = new HashSet(this.dateMap.values());
           if (!dates.isEmpty()) {
               //ICookRecipeDetailService menuRecipeDetailService = SpringContextHolder.getBean(ICookRecipeDetailService.class);
               CookRecipeDetailMapper cookRecipeDetailMapper = SpringContextHolder.getBean(CookRecipeDetailMapper.class);
               CookRecipeDishesMapper cookRecipeDishesMapper = SpringContextHolder.getBean(CookRecipeDishesMapper.class);
               //List<CookRecipeDetail> byRecipeIdAndDates = menuRecipeDetailService.getByRecipeIdAndDatesAndIntervalId(this.recipeId, dates, this.mealtimeType);
               List<CookRecipeDetail> byRecipeIdAndDates = cookRecipeDetailMapper.getByRecipeIdAndDatesAndIntervalId(this.recipeId, dates, this.mealtimeType);
               Map<LocalDate, CookRecipeDetail> dateDetailMap = byRecipeIdAndDates.stream().collect(Collectors.groupingBy(CookRecipeDetail::getApplyDate, Collectors.collectingAndThen(Collectors.toList(), (list) -> {
                   return list.get(0);
               })));
               if (!this.dishesNames.isEmpty()) {
                   //ICookDishesService menuDishesService = SpringContextHolder.getBean(ICookDishesService.class);
                   //List<CookDishes> menuDishesList = menuDishesService.getByNames(this.dishesNames);
                   CookDishesMapper cookDishesMapper = SpringContextHolder.getBean(CookDishesMapper.class);
                   CookDishes cookDishes = new CookDishes();
                   cookDishes.setDishesNames(this.dishesNames);
                   List<CookDishes> cookDishesList = cookDishesMapper.selectCookDishesList(cookDishes);

                   Set<String> difference = DifferenceCalculator.calculateDifference(this.dishesNames, cookDishesList);
                   System.out.println("差集结果: " + difference);
                   if (difference != null && difference.size() > 0) {
                       throw new ServiceException("以下菜品不存在:" + difference);
                   }
                   Map<String, CookDishes> nameMap = cookDishesList.stream().collect(Collectors.groupingBy(CookDishes::getDishesName, Collectors.collectingAndThen(Collectors.toList(), (list) -> {
                       return list.get(0);
                   })));
                   //ICookRecipeDishesService menuRecipeDishesService = SpringContextHolder.getBean(ICookRecipeDishesService.class);
                   List<CookRecipeDishes> inserData = new ArrayList<>();

                   for (LocalDate date : dates) {
                       CookRecipeDetail cookRecipeDetail = dateDetailMap.get(date);
                       if (cookRecipeDetail == null) {
                           cookRecipeDetail = new CookRecipeDetail();
                           cookRecipeDetail.setRecipeId(this.recipeId);
                           cookRecipeDetail.setApplyDate(date);
                           cookRecipeDetail.setMealtimeType(this.mealtimeType);
                           //menuRecipeDetail.setDetailId(Id.next());
                           //menuRecipeDetailService.save(menuRecipeDetail);
                           cookRecipeDetailMapper.insertCookRecipeDetail(cookRecipeDetail);
                       } else {
                           //menuRecipeDishesService.deleteByDetailId(menuRecipeDetail.getDetailId());
                           Long[] recipeDetailIds = {cookRecipeDetail.getRecipeDetailId()};
                           cookRecipeDishesMapper.deleteCookRecipeDishesByCookRecipeDetailIds(recipeDetailIds);
                       }

                       List<ImportRecipeDishesDTO> importRecipeDishesDtos = this.datas.get(date);
                       CookRecipeDetail finalCookRecipeDetail = cookRecipeDetail;
                       List<CookRecipeDishes> saveDatas = importRecipeDishesDtos.stream().filter(distinctByKey(ImportRecipeDishesDTO::getDishesName)).map((importRecipeDishesDto) -> {
                           CookRecipeDishes cookRecipeDishes = null;
                           CookDishes cookDishesValue = nameMap.get(importRecipeDishesDto.getDishesName());
                           if (cookDishesValue != null) {
                               cookRecipeDishes = BeanUtil.copyProperties(importRecipeDishesDto, CookRecipeDishes.class, new String[0]);
                               cookRecipeDishes.setRecipeDetailId(finalCookRecipeDetail.getRecipeDetailId());
                               cookRecipeDishes.setSizeType(cookDishesValue.getSizeType());
                               cookRecipeDishes.setDishesId(cookDishesValue.getDishesId());
                           } else {
                               this.notImportDishesNames.add(importRecipeDishesDto.getDishesName());
                           }

                           return cookRecipeDishes;
                       }).filter(Objects::nonNull).collect(Collectors.toList());
                       inserData.addAll(saveDatas);
                   }

                   //menuRecipeDishesService.saveBatch(inserData);
                   for (CookRecipeDishes cookRecipeDishes : inserData) {
                       cookRecipeDishesMapper.insertCookRecipeDishes(cookRecipeDishes);
                   }
               }
           }

       }catch (Exception e){
           throw new ServiceException(e.getMessage());
       }
   }

   static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
      Map<Object, Boolean> seen = new ConcurrentHashMap<>();
      return (t) -> {
         return seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
      };
   }

}
