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

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.menu.domain.MenuDishes;
import com.bonus.canteen.core.menu.domain.MenuRecipeDetail;
import com.bonus.canteen.core.menu.domain.MenuRecipeDishes;
import com.bonus.canteen.core.menu.dto.ImportRecipeDishesDto;
import com.bonus.canteen.core.menu.service.IMenuDishesService;
import com.bonus.canteen.core.menu.service.IMenuRecipeDetailService;
import com.bonus.canteen.core.menu.service.IMenuRecipeDishesService;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.houqin.utils.id.Id;
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 MenuRecipeImportListener extends AnalysisEventListener<Map<Integer, String>> {
   private static final Logger log = LoggerFactory.getLogger(MenuRecipeImportListener.class);
   private final String sheetName;
   private final Long recipeId;
   private final Integer 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 MenuRecipeImportListener(String sheetName, Long recipeId, Integer 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()) {
               IMenuRecipeDetailService menuRecipeDetailService = SpringContextHolder.getBean(IMenuRecipeDetailService.class);
               List<MenuRecipeDetail> byRecipeIdAndDates = menuRecipeDetailService.getByRecipeIdAndDatesAndIntervalId(this.recipeId, dates, this.mealtimeType);
               Map<LocalDate, MenuRecipeDetail> dateDetailMap = byRecipeIdAndDates.stream().collect(Collectors.groupingBy(MenuRecipeDetail::getApplyDate, Collectors.collectingAndThen(Collectors.toList(), (list) -> {
                   return list.get(0);
               })));
               if (!this.dishesNames.isEmpty()) {
                   IMenuDishesService menuDishesService = SpringContextHolder.getBean(IMenuDishesService.class);
                   List<MenuDishes> menuDishesList = menuDishesService.getByNames(this.dishesNames);

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

                   for (LocalDate date : dates) {
                       MenuRecipeDetail menuRecipeDetail = dateDetailMap.get(date);
                       if (menuRecipeDetail == null) {
                           menuRecipeDetail = new MenuRecipeDetail();
                           menuRecipeDetail.setRecipeId(this.recipeId);
                           menuRecipeDetail.setApplyDate(date);
                           menuRecipeDetail.setMealtimeType(this.mealtimeType);
                           menuRecipeDetail.setDetailId(Id.next());
                           menuRecipeDetailService.save(menuRecipeDetail);
                       } else {
                           menuRecipeDishesService.deleteByDetailId(menuRecipeDetail.getDetailId());
                       }

                       List<ImportRecipeDishesDto> importRecipeDishesDtos = this.datas.get(date);
                       MenuRecipeDetail finalMenuRecipeDetail = menuRecipeDetail;
                       List<MenuRecipeDishes> saveDatas = importRecipeDishesDtos.stream().filter(distinctByKey(ImportRecipeDishesDto::getDishesName)).map((importRecipeDishesDto) -> {
                           MenuRecipeDishes menuRecipeDishes = null;
                           MenuDishes menuDishes = nameMap.get(importRecipeDishesDto.getDishesName());
                           if (menuDishes != null) {
                               menuRecipeDishes = BeanUtil.copyProperties(importRecipeDishesDto, MenuRecipeDishes.class, new String[0]);
                               menuRecipeDishes.setDetailId(finalMenuRecipeDetail.getDetailId());
                               menuRecipeDishes.setSizeType(menuDishes.getSizeType());
                               menuRecipeDishes.setDishesId(menuDishes.getDishesId());
                           } else {
                               this.notImportDishesNames.add(importRecipeDishesDto.getDishesName());
                           }

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

                   menuRecipeDishesService.saveBatch(inserData);
               }
           }

       }catch (Exception e){
           throw new RuntimeException(e);
       }
   }

   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;
      };
   }

}
