package com.bonus.core.menu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.constant.DelFlagEnum;
import com.bonus.constant.LeConstants;
import com.bonus.core.allocation.api.AllocDeliveryApi;
import com.bonus.core.allocation.api.AllocMealtimeApi;
import com.bonus.core.allocation.canteen.model.AllocDeliveryCostModel;
import com.bonus.core.common.redis.RedisUtil;
import com.bonus.core.common.utils.TenantContextHolder;
import com.bonus.core.menu.dto.CheckDishesDto;
import com.bonus.core.menu.dto.OrderRecipeDishesDto;
import com.bonus.core.menu.entity.MenuDishes;
import com.bonus.core.menu.entity.MenuRecipe;
import com.bonus.core.menu.entity.MenuRecipeDetail;
import com.bonus.core.menu.entity.MenuRecipeDishes;
import com.bonus.core.menu.mapper.MenuRecipeDishesMapper;
import com.bonus.core.menu.mapper.MenuRecipeMapper;
import com.bonus.core.menu.model.AllocMealtimeStateModel;
import com.bonus.core.menu.service.MenuDishesService;
import com.bonus.core.menu.service.MenuRecipeDetailService;
import com.bonus.core.menu.service.MenuRecipeDishesService;
import com.bonus.core.menu.vo.CheckDishesVo;
import com.bonus.core.order.common.constants.OrderTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.invoke.SerializedLambda;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class MenuRecipeDishesServiceImpl extends ServiceImpl<MenuRecipeDishesMapper, MenuRecipeDishes> implements MenuRecipeDishesService {
   private static final Logger log = LoggerFactory.getLogger(MenuRecipeDishesServiceImpl.class);

   @Resource
   private MenuRecipeDishesMapper menuRecipeDishesMapper;
   @Autowired
   @Lazy
   private MenuRecipeDetailService menuRecipeDetailService;
   @Autowired
   @Lazy
   private MenuDishesService menuDishesService;
   @Autowired
   private MenuRecipeMapper menuRecipeMapper;
   @Autowired
   private AllocDeliveryApi allocDeliveryApi;
   @Autowired
   private AllocMealtimeApi allocMealtimeApi;

   @Override
   public boolean saveBatch(Collection<MenuRecipeDishes> entityList) {
      Iterator var2 = CollUtil.split(entityList, 500).iterator();

      while(var2.hasNext()) {
         List<MenuRecipeDishes> menuRecipeDishes = (List)var2.next();
         menuRecipeDishesMapper.insertValues(menuRecipeDishes);
      }

      return true;
   }

   public OrderRecipeDishesDto getOrderDishesDetail(Long detailId, Long dishesId) {
      MenuRecipeDetail menuRecipeDetail = this.menuRecipeDetailService.getOne(Wrappers
              .lambdaQuery(MenuRecipeDetail.class).select(MenuRecipeDetail::getRecipeId)
              .eq(MenuRecipeDetail::getDetailId, detailId));
      if (ObjectUtil.isNull(menuRecipeDetail)) {
         throw new ServiceException("菜谱已更新,请刷新页面重新点餐");
      } else {
         String redisKey = String.format("yst:%s:recipe:%s:detail:%s:dishes:%s:order:query", TenantContextHolder.getTenantId(), menuRecipeDetail.getRecipeId(), detailId, dishesId);
         Object obj = RedisUtil.getObj(redisKey);
         if (obj instanceof OrderRecipeDishesDto) {
            OrderRecipeDishesDto o = (OrderRecipeDishesDto)obj;
            log.info("取redis缓存,详情: {}", JSON.toJSONString(obj));
            return o;
         } else {
            MenuRecipeDishes menuRecipeDishes = this.getOne(Wrappers
                    .lambdaQuery(MenuRecipeDishes.class).eq(MenuRecipeDishes::getDishesId, dishesId)
                    .eq(MenuRecipeDishes::getDetailId, detailId));
            MenuDishes menuDishes = this.menuDishesService.getOne(Wrappers
                    .lambdaQuery(MenuDishes.class).eq(MenuDishes::getDishesId, dishesId));
            OrderRecipeDishesDto orderRecipeDishesDto = BeanUtil.copyProperties(menuRecipeDishes, OrderRecipeDishesDto.class);
            orderRecipeDishesDto.setSalesMode(menuDishes.getSalesMode());
            orderRecipeDishesDto.setUnitPrice(menuDishes.getUnitPrice());
            orderRecipeDishesDto.setImageUrl(menuDishes.getImageUrl());
            orderRecipeDishesDto.setDishesName(menuDishes.getDishesName());
            log.info("查询数据库信息,详情: {}", JSON.toJSONString(orderRecipeDishesDto));
            RedisUtil.setObj(redisKey, orderRecipeDishesDto, 86400L);
            return orderRecipeDishesDto;
         }
      }
   }

   public List<CheckDishesVo> checkDishes(List<CheckDishesDto> checkDishes, Integer orderType) {
      List<Long> dishesIds = checkDishes.stream().map(CheckDishesDto::getGoodsDishesId).collect(Collectors.toList());
      Map<Long, MenuDishes> dishesMap = this.menuDishesService.getMenuDishesList(dishesIds).stream().collect(Collectors.toMap(MenuDishes::getDishesId, Function.identity()));
      return checkDishes.stream().map((checkDish) -> {
         CheckDishesVo checkDishesVo = this.initCheckDishesVo(dishesMap, checkDish);
         MenuRecipeDetail menuRecipeDetail = this.menuRecipeDetailService.getByRecipeIdAndApplyDateAndIntervalId(checkDish.getRecipeId(), checkDish.getOrderDate(), checkDish.getMealtimeType());
         if (ObjectUtil.isEmpty(menuRecipeDetail)) {
            checkDishesVo.setIfExpired(LeConstants.COMMON_YES);
            return checkDishesVo;
         } else {
            Long detailId = menuRecipeDetail.getDetailId();
            Long stallId = this.menuRecipeMapper.selectStallIdByWrappers(Wrappers
                    .lambdaQuery(MenuRecipe.class).eq(MenuRecipe::getRecipeId, menuRecipeDetail.getRecipeId())
                    .eq(MenuRecipe::getDelFlag, DelFlagEnum.DEL_FALSE.key()));
            List<AllocDeliveryCostModel> costModelList = this.allocDeliveryApi.queryDeliveryCostModel(stallId);
            checkDishesVo.setCostModelList(costModelList);
            List<AllocMealtimeStateModel> mealTimeList = this.allocMealtimeApi.getAllocMealtimeMenuModel(stallId)
                    .getMealtimeStateModelList();
            if (ObjectUtil.isNotEmpty(mealTimeList)) {
               mealTimeList = mealTimeList.stream().filter((mealtime) -> {
                  return mealtime.getIfUse() == 1;
               }).collect(Collectors.toList());
            }

            if (LocalDate.now().isEqual(menuRecipeDetail.getApplyDate()) && !OrderTypeEnum.isCurrMealType(orderType)) {
               mealTimeList = mealTimeList.stream().filter((time) -> {
                  return LocalTime.now().isBefore(time.getStartTime());
               }).collect(Collectors.toList());
            } else if (LocalDate.now().isAfter(menuRecipeDetail.getApplyDate())) {
               mealTimeList = null;
            }

            MenuRecipeDishes menuRecipeDishes = this.baseMapper
                    .selectOne(Wrappers.lambdaQuery(MenuRecipeDishes.class)
                            .eq(MenuRecipeDishes::getDetailId, detailId).eq(MenuRecipeDishes::getDishesId,
                            checkDish.getGoodsDishesId()));
            if (ObjectUtil.isEmpty(menuRecipeDishes)) {
               checkDishesVo.setIfExpired(LeConstants.COMMON_YES);
               return checkDishesVo;
            } else {
               BeanUtil.copyProperties(menuRecipeDishes, checkDishesVo, new String[0]);
               checkDishesVo.setIfExpired(LeConstants.COMMON_NO);
               checkDishesVo.setMenuDetailId(detailId);
               checkDishesVo.setSalePrice(BigDecimal.valueOf((long)menuRecipeDishes.getPrice()));
               checkDishesVo.setPrefPrice(BigDecimal.valueOf((long)menuRecipeDishes.getSalePrice()));
               if (ObjectUtil.isEmpty(mealTimeList)) {
                  checkDishesVo.setIfExpired(LeConstants.COMMON_YES);
                  return checkDishesVo;
               } else {
                  boolean contains = mealTimeList.stream().map(AllocMealtimeStateModel::getMealtimeType)
                          .collect(Collectors.toList()).contains(checkDish.getMealtimeType());
                  if (contains) {
                     checkDishesVo.setIfExpired(LeConstants.COMMON_NO);
                  } else {
                     checkDishesVo.setIfExpired(LeConstants.COMMON_YES);
                  }

                  return checkDishesVo;
               }
            }
         }
      }).collect(Collectors.toList());
   }

   public CheckDishesVo initCheckDishesVo(Map<Long, MenuDishes> dishesMap, CheckDishesDto checkDish) {
      CheckDishesVo checkDishesVo = new CheckDishesVo();
      checkDishesVo.setIfExpired(LeConstants.COMMON_YES);
      checkDishesVo.setRecipeId(checkDish.getRecipeId());
      MenuDishes menuDishes = (MenuDishes)dishesMap.get(checkDish.getGoodsDishesId());
      if (ObjectUtil.isNotEmpty(menuDishes)) {
         checkDishesVo.setGoodsDishesName(menuDishes.getDishesName());
         checkDishesVo.setWeightUnit(menuDishes.getUnitPrice());
         checkDishesVo.setSalesMode(menuDishes.getSalesMode());
         checkDishesVo.setSizeJson(menuDishes.getSizeJson());
         checkDishesVo.setSizeType(menuDishes.getSizeType());
         checkDishesVo.setImageUrl(menuDishes.getImageUrl());
      }

      checkDishesVo.setOrderDate(checkDish.getOrderDate());
      checkDishesVo.setMealtimeType(checkDish.getMealtimeType());
      checkDishesVo.setGoodsDishesId(checkDish.getGoodsDishesId());
      return checkDishesVo;
   }

}
