package com.bonus.core.order.mobile.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import com.bonus.core.allocation.canteen.model.AllocCanteen;
import com.bonus.core.allocation.canteen.model.AllocStall;
import com.bonus.core.common.enums.AllocMealtimeTypeEnum;
import com.bonus.core.common.utils.JavaxValidateUtils;
import com.bonus.core.common.utils.LogUtil;
import com.bonus.core.menu.api.MenuRecipeApi;
import com.bonus.core.menu.dto.CheckDishesDto;
import com.bonus.core.menu.model.AllocMealtimeModel;
import com.bonus.core.menu.vo.CheckDishesVo;
import com.bonus.core.order.common.constants.DetailTypeEnum;
import com.bonus.core.order.common.constants.OrderTips;
import com.bonus.core.order.common.constants.OrderTypeEnum;
import com.bonus.core.order.common.dto.OrderDetailPayDTO;
import com.bonus.core.order.common.model.OrderShoppingCart;
import com.bonus.core.order.common.service.OrderShoppingCartService;
import com.bonus.core.order.custom.OrderCustomBusiness;
import com.bonus.core.order.mobile.dto.OrderShoppingCartAddDTO;
import com.bonus.core.order.mobile.dto.OrderShoppingCartClearDTO;
import com.bonus.core.order.mobile.dto.OrderShoppingCartUpdateDTO;
import com.bonus.core.order.mobile.dto.OrderShoppingSearchDTO;
import com.bonus.core.order.mobile.service.ShoppingCartBusiness;
import com.bonus.core.order.mobile.vo.OrderShoppingCartAddResultVO;
import com.bonus.core.order.mobile.vo.OrderShoppingCartListMobileVO;
import com.bonus.core.order.utils.LeNumUtil;
import com.bonus.core.supermarket.api.SupermarketApi;
import com.bonus.core.supermarket.dto.SupermarketNotRemovedProductListDTO;
import com.bonus.core.supermarket.model.SupermarketInfo;
import com.bonus.core.supermarket.vo.SupermarketNotRemovedProductListVO;
import com.bonus.i18n.I18n;
import com.bonus.utils.id.Id;
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 java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ShoppingCartBusinessImpl implements ShoppingCartBusiness {
   private static final Logger log = LoggerFactory.getLogger(ShoppingCartBusinessImpl.class);

   @Autowired
   @Lazy
   protected OrderShoppingCartService orderShoppingCartService;
   @Autowired
   @Lazy
   protected OrderCustomBusiness orderCustomBusiness;
   @Autowired
   @Lazy
   protected SupermarketApi supermarketApi;
   @Autowired
   @Lazy
   protected MenuRecipeApi menuRecipeApi;

   @Override
   public OrderShoppingCartAddResultVO add(OrderShoppingCartAddDTO addDTO) {
      OrderShoppingCartAddResultVO customVO = this.orderCustomBusiness.mobile().willAddShoppingCart(addDTO);
      if (customVO != null) {
         return customVO;
      } else {
         try{
            this.checkSubmitParam(addDTO);
         }catch (Exception e){

         }
//         RLock lock = RedisUtil.getLock(OrderCacheConstants.shoppingCartLockKey(addDTO.getCustId()));
         OrderShoppingCart entity;
         try {
            OrderShoppingCart sameShoppingCart = (OrderShoppingCart)this.orderShoppingCartService.listByCust((new OrderShoppingSearchDTO()).setCustId(addDTO.getCustId()).setOrderType(addDTO.getOrderType())).stream().filter((s) -> {
               return this.isSameDishes(s, addDTO);
            }).findFirst().orElse(null);
            if (sameShoppingCart != null) {
               log.info("购物车已存在，更新数量：{} {} {}", new Object[]{sameShoppingCart.getShoppingCartId(), sameShoppingCart.getQuantity(), addDTO.getQuantity()});
               entity = sameShoppingCart;
               this.orderShoppingCartService.plusQuantity(sameShoppingCart.getShoppingCartId(), addDTO.getQuantity());
               sameShoppingCart.setQuantity(sameShoppingCart.getQuantity() + addDTO.getQuantity());
            } else {
               log.info("购物车不存在，新增：{}", addDTO);
               entity = addDTO.convertToEntity();
               entity.setShoppingCartId(Id.next());
               if (OrderTypeEnum.isCurrMealType(addDTO.getOrderType())) {
                  addDTO.setOrderDate((LocalDate)null);
                  addDTO.setMealtimeType((Integer)null);
               }
               this.orderShoppingCartService.insert(entity);
            }
         } finally {
            try {
//               if (lock.isHeldByCurrentThread() && lock.isLocked()) {
//                  lock.unlock();
//               }
            } catch (Exception var11) {
               log.error("解锁异常", var11);
            }

         }

         OrderShoppingCartAddResultVO resultVO = OrderShoppingCartAddResultVO.of(entity);
         return this.orderCustomBusiness.mobile().didAddShoppingCart(addDTO, resultVO);
      }
   }

   @Override
   public void update(OrderShoppingCartUpdateDTO updateDTO) {
      if (this.orderCustomBusiness.mobile().willUpdateShoppingCart(updateDTO)) {
         JavaxValidateUtils.validate(updateDTO);
         if (updateDTO.getQuantity() > 0) {
            this.orderShoppingCartService.updateQuantity(updateDTO.getShoppingCartId(), updateDTO.getQuantity());
         } else {
            this.orderShoppingCartService.removeByIds(CollUtil.newArrayList(new Long[]{updateDTO.getShoppingCartId()}));
         }
         this.orderCustomBusiness.mobile().didUpdateShoppingCart(updateDTO);
      }
   }

   @Override
   public void clear(OrderShoppingCartClearDTO removeDTO) {
      if (this.orderCustomBusiness.mobile().willClearShoppingCart(removeDTO.getShoppingCartIds())) {
         JavaxValidateUtils.validate(removeDTO);
         this.orderShoppingCartService.removeByIds(removeDTO.getShoppingCartIds());
         this.orderCustomBusiness.mobile().didClearShoppingCart(removeDTO.getShoppingCartIds());
      }
   }

   @Override
   public List<OrderShoppingCartListMobileVO> listByCust(OrderShoppingSearchDTO searchDTO) {
      JavaxValidateUtils.validate(searchDTO);
      List<OrderShoppingCart> orderShoppingCarts = this.orderShoppingCartService.listByCust(searchDTO);
      LogUtil.infoFieldsX("查询购物车_结果", orderShoppingCarts, OrderShoppingCart.logFields());
      List<OrderShoppingCartListMobileVO> voList = (List)orderShoppingCarts.stream().map(OrderShoppingCartListMobileVO::of).collect(Collectors.toList());
      if (CollUtil.isEmpty(voList)) {
         return voList;
      } else {
         this.fillVo(voList, searchDTO.getOrderType(), searchDTO.getCustId());
         return this.orderCustomBusiness.mobile().didListShoppingCartByCust(searchDTO, voList);
      }
   }

   protected void fillVo(List<OrderShoppingCartListMobileVO> voList, Integer orderType, Long custId) {
      if (!CollUtil.isEmpty(voList)) {
         if (OrderTypeEnum.isShopCategory(orderType)) {
            Map<Long, List<OrderShoppingCartListMobileVO>> voGroupBySupermarket = (Map)voList.stream().collect(Collectors.groupingBy(OrderShoppingCartListMobileVO::getCanteenId));
            voGroupBySupermarket.forEach((supermarketId, vos) -> {
               List<Long> goodsIds = (List)vos.stream().map(OrderShoppingCartListMobileVO::getGoodsDishesId).collect(Collectors.toList());
               SupermarketNotRemovedProductListDTO dto = new SupermarketNotRemovedProductListDTO();
               dto.setSupermarketId(supermarketId);
               dto.setMaterialIdList(goodsIds);
               dto.setCustId(custId);
               Map<Long, SupermarketNotRemovedProductListVO> productMap =null;
//                       (Map)this.supermarketApi.listNotRemovedProduct(dto).stream().collect(Collectors.toMap(SupermarketNotRemovedProductListVO::getMaterialId, Function.identity()));
               vos.forEach((s) -> {
                  s.fillSupermarketProductInfo((SupermarketNotRemovedProductListVO)productMap.get(s.getGoodsDishesId()));
               });
            });
         } else if (OrderTypeEnum.isCanteenCategory(orderType)) {
            if (OrderTypeEnum.isCurrMealType(orderType)) {
               voList.forEach((s) -> {
                  AllocMealtimeModel nowMealtime = null;
//                          this.orderModuleClient.mealtimeQuery(MealtimeQueryParam.ofAssignTime(LocalTime.now(), s.getCanteenId(), s.getStallId()));
                  if (nowMealtime != null) {
                     s.setOrderDate(LocalDate.now());
                     s.setMealtimeType(nowMealtime.getMealtimeType());
                  }

               });
            }

            List<CheckDishesDto> checkDtoList = voList.stream().map((s) -> {
               CheckDishesDto checkDishesDto = new CheckDishesDto();
               checkDishesDto.setGoodsDishesId(s.getGoodsDishesId());
               checkDishesDto.setRecipeId(s.getMenuId());
               checkDishesDto.setOrderDate(s.getOrderDate());
               checkDishesDto.setMealtimeType(s.getMealtimeType());
               return checkDishesDto;
            }).collect(Collectors.toList());
            LogUtil.info("查询菜品过期_入参：", checkDtoList);
            List<CheckDishesVo> checkDishesVoList = this.menuRecipeApi.checkDishes(checkDtoList, orderType);
            LogUtil.info("查询菜品过期_结果：", checkDishesVoList);
            voList.forEach((s) -> {
               Optional<CheckDishesVo> var10000 = checkDishesVoList.stream().filter((o) -> {
                  return this.isSameDishes(s, o);
               }).findFirst();
               Objects.requireNonNull(s);
               var10000.ifPresent(s::fillDishesInfo);
            });
         }

         this.fillCanteenStallMealtimeName(voList);
      }
   }
   protected boolean isSameDishes(OrderShoppingCartListMobileVO cart, CheckDishesVo checkDishes) {
      if (OrderTypeEnum.isCurrMealType(cart.getOrderType())) {
         return cart.getGoodsDishesId().equals(checkDishes.getGoodsDishesId()) && cart.getMenuId().equals(checkDishes.getRecipeId());
      } else {
         return cart.getGoodsDishesId().equals(checkDishes.getGoodsDishesId()) && cart.getMenuId().equals(checkDishes.getRecipeId()) && cart.getOrderDate().equals(checkDishes.getOrderDate()) && cart.getMealtimeType().equals(checkDishes.getMealtimeType());
      }
   }
   protected boolean isSameDishes(OrderShoppingCart cart, OrderShoppingCartAddDTO addDTO) {
      if (OrderTypeEnum.isShopCategory(addDTO.getOrderType()) && OrderTypeEnum.isShopCategory(cart.getOrderType())) {
         return cart.getGoodsDishesId().equals(addDTO.getGoodsDishesId()) && cart.getCanteenId().equals(addDTO.getCanteenId());
      } else if (OrderTypeEnum.isCurrMealType(addDTO.getOrderType()) && OrderTypeEnum.isCurrMealType(cart.getOrderType())) {
         return cart.getGoodsDishesId().equals(addDTO.getGoodsDishesId()) && cart.getMenuId().equals(addDTO.getMenuId()) && cart.getCanteenId().equals(addDTO.getCanteenId()) && cart.getStallId().equals(addDTO.getStallId());
      } else {
         return cart.getGoodsDishesId().equals(addDTO.getGoodsDishesId()) && cart.getMenuId().equals(addDTO.getMenuId()) && cart.getCanteenId().equals(addDTO.getCanteenId()) && cart.getStallId().equals(addDTO.getStallId()) && cart.getOrderDate().equals(addDTO.getOrderDate()) && cart.getMealtimeType().equals(addDTO.getMealtimeType());
      }
   }
   protected void fillCanteenStallMealtimeName(List<OrderShoppingCartListMobileVO> voList) {
      Map<Long, String> canteenNameMapById = MapUtil.newHashMap();
      Map<Long, AllocStall> stallMapById = MapUtil.newHashMap();

      OrderShoppingCartListMobileVO vo;
      for(Iterator var4 = voList.iterator(); var4.hasNext(); vo.setMealtimeName(AllocMealtimeTypeEnum.getDescByKey(vo.getMealtimeType()))) {
         vo = (OrderShoppingCartListMobileVO)var4.next();
         if (LeNumUtil.isValidId(vo.getCanteenId())) {
            if (!canteenNameMapById.containsKey(vo.getCanteenId())) {
               if (OrderTypeEnum.isShopCategory(vo.getOrderType())) {
                  SupermarketInfo supermarketInfo = null;
//                          this.supermarketApi.getSupermarketInfoById(vo.getCanteenId());
                  if (supermarketInfo != null) {
                     canteenNameMapById.put(vo.getCanteenId(), supermarketInfo.getSupermarketName());
                  }
               } else {
                  AllocCanteen allocCanteen = null;
//                          this.allocCanteenApi.getAllocCanteen(vo.getCanteenId());
                  if (allocCanteen != null) {
                     canteenNameMapById.put(vo.getCanteenId(), allocCanteen.getCanteenName());
                  }
               }
            }

            vo.setCanteenName((String)canteenNameMapById.get(vo.getCanteenId()));
         }

         if (LeNumUtil.isValidId(vo.getStallId())) {
            AllocStall allocStall;
            if (stallMapById.containsKey(vo.getStallId())) {
               allocStall =null;
//                       this.allocStallApi.getAllocStall(vo.getStallId());
               if (allocStall != null) {
                  stallMapById.put(vo.getStallId(), allocStall);
               }
            }

            allocStall =null;
//                    this.allocStallApi.getAllocStall(vo.getStallId());
            if (allocStall != null) {
               vo.setStallName(allocStall.getStallName());
            }
         }
      }
   }
   protected void checkSubmitParam(OrderShoppingCartAddDTO addDTO) throws Exception {
      JavaxValidateUtils.validate(addDTO);
      if (!this.supportOrderTypes().contains(addDTO.getOrderType())) {
         throw new Exception(I18n.getMessage("order.un-support-order-type", new Object[0]));
      } else {
         if (OrderTypeEnum.isCanteenCategory(addDTO.getOrderType())) {
            if (addDTO.getOrderDate() == null || !LeNumUtil.isValidId(addDTO.getMealtimeType())) {
               throw new Exception(I18n.getMessage("order.mobile.cart-need-date-mealtime", new Object[0]));
            }

            if (!DetailTypeEnum.isDishesCategory(addDTO.getDetailType())) {
               throw new Exception(I18n.getMessage("order.un-support-detail-type", new Object[0]));
            }

            if (!LeNumUtil.isValidId(addDTO.getMenuId())) {
               throw new Exception(OrderTips.paramIllegal("：menuId（菜谱id）"));
            }

            if (!LeNumUtil.isValidId(addDTO.getCanteenId())) {
               throw new Exception(OrderTips.paramIllegal("：canteenId（食堂id）"));
            }

            if (!LeNumUtil.isValidId(addDTO.getStallId())) {
               throw new Exception(OrderTips.paramIllegal("：stallId（档口id）"));
            }
         } else if (OrderTypeEnum.isShopCategory(addDTO.getOrderType())) {
            if (!DetailTypeEnum.isProductType(addDTO.getDetailType())) {
               throw new Exception(I18n.getMessage("order.un-support-detail-type", new Object[0]));
            }

            if (!LeNumUtil.isValidId(addDTO.getCanteenId())) {
               throw new Exception(OrderTips.paramIllegal("：canteenId（超市id）"));
            }
         }

      }
   }
   public List<Integer> supportOrderTypes() {
      return CollUtil.toList(new Integer[]{OrderTypeEnum.CURR_MEAL.getKey(), OrderTypeEnum.RESERVE_MEAL.getKey()
              , OrderTypeEnum.SHOP.getKey(), OrderTypeEnum.RESERVE_SHOP.getKey()});
   }

   public List<OrderDetailPayDTO> filterInvalidByCartIds(Integer orderType, Long custId, List<OrderDetailPayDTO> orderDetailPayDTOList) {
      if (CollUtil.isEmpty(orderDetailPayDTOList)) {
         return CollUtil.newArrayList(new OrderDetailPayDTO[0]);
      } else {
         List<OrderDetailPayDTO> customList = this.orderCustomBusiness.mobile().willFilterInvalidByCartIds(orderType, custId, orderDetailPayDTOList);
         if (customList != null) {
            return customList;
         } else {
            List<Long> shoppingCartIds = orderDetailPayDTOList.stream().filter((s) -> {
               return LeNumUtil.isValidId(s.getShoppingCartId());
            }).map(OrderDetailPayDTO::getShoppingCartId).collect(Collectors.toList());
            if (CollUtil.isEmpty(shoppingCartIds)) {
               return orderDetailPayDTOList;
            } else {
               List<OrderShoppingCartListMobileVO> voList = this.orderShoppingCartService.listByIds(shoppingCartIds).stream().map(OrderShoppingCartListMobileVO::of).collect(Collectors.toList());
               this.fillVo(voList, orderType, custId);
               List<Long> invalidCartIds = voList.stream().filter(OrderShoppingCartListMobileVO::ifInvalid).map(OrderShoppingCartListMobileVO::getShoppingCartId).collect(Collectors.toList());
               List<OrderDetailPayDTO> resultList = orderDetailPayDTOList.stream().filter((s) -> {
                  return !invalidCartIds.contains(s.getShoppingCartId());
               }).collect(Collectors.toList());
               return this.orderCustomBusiness.mobile().didFilterInvalidByCartIds(orderType, custId, orderDetailPayDTOList, resultList);
            }
         }
      }
   }

   public void clearAfterPlaced(List<Long> shoppingCartIds) {
      if (!CollUtil.isEmpty(shoppingCartIds)) {
         if (this.orderCustomBusiness.mobile().willClearShoppingCart(shoppingCartIds)) {
            this.orderShoppingCartService.removeByIds(shoppingCartIds);
            this.orderCustomBusiness.mobile().didClearShoppingCart(shoppingCartIds);
         }
      }
   }
}
