package com.bonus.canteen.core.order.android.business.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.bonus.canteen.core.allocation.api.AllocStallApi;
import com.bonus.canteen.core.allocation.canteen.model.AllocStall;
import com.bonus.canteen.core.common.redis.RedisUtil;
import com.bonus.canteen.core.customer.constants.OrderTypeEnum;
import com.bonus.canteen.core.customer.vo.CustPayVO;
import com.bonus.canteen.core.order.android.business.OrderDishesAndroidBusiness;
import com.bonus.canteen.core.order.android.vo.OrderCallListVO;
import com.bonus.canteen.core.order.android.vo.OrderListAndroidVO;
import com.bonus.canteen.core.order.client.OrderModuleClient;
import com.bonus.canteen.core.order.client.po.CustPayInfoQueryParam;
import com.bonus.canteen.core.order.common.constants.DishesStateEnum;
import com.bonus.canteen.core.order.common.constants.OrderCacheConstants;
import com.bonus.canteen.core.order.common.constants.OrderStateEnum;
import com.bonus.canteen.core.order.common.dto.OrderSearchParam;
import com.bonus.canteen.core.order.common.model.OrderInfo;
import com.bonus.canteen.core.order.common.query.OrderQueryHelper;
import com.bonus.canteen.core.order.common.service.OrderDetailService;
import com.bonus.canteen.core.order.common.service.OrderInfoService;
import com.bonus.canteen.core.order.common.vo.OrderIdDateVO;
import com.bonus.canteen.core.order.custom.OrderCustomBusiness;
import com.bonus.canteen.core.order.deprecated.constants.OrderStateOldEnum;
import com.bonus.canteen.core.order.mq.OrderMessageSend;
import com.bonus.canteen.core.order.utils.LeNumUtil;
import com.bonus.canteen.core.order.web.dto.OrderUserPermissionDTO;
import com.bonus.canteen.core.supermarket.api.SupermarketApi;
import com.bonus.canteen.core.supermarket.model.SupermarketInfo;
import org.redisson.api.RLock;
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.time.LocalTime;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

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

   @Autowired
   @Lazy
   protected OrderCustomBusiness orderCustomBusiness;

   @Autowired
   @Lazy
   protected AllocStallApi allocStallApi;
   @Autowired
   @Lazy
   protected SupermarketApi supermarketApi;
   @Lazy
   @Autowired
   protected LeNumUtil numUtil;
   @Autowired
   @Lazy
   protected OrderInfoService orderInfoService;
   @Autowired
   @Lazy
   protected OrderDetailService orderDetailService;
   @Autowired
   @Lazy
   protected OrderModuleClient orderModuleClient;

   public void initOrderMealCode(OrderInfo orderInfo) {
      if (!CharSequenceUtil.isNotEmpty(orderInfo.getMealCode())) {
         String mealCode = this.createMealCode(orderInfo.getOrderType(), orderInfo.getCanteenId(), orderInfo.getStallId(), orderInfo.getOrderDate(), orderInfo.getMealtimeType());
         orderInfo.setMealCode(mealCode);
      }
   }

   public String createMealCode(Integer orderType, Long canteenId, Long stallId, LocalDate orderDate, Integer mealtimeType) {
      String mealCode = this.orderCustomBusiness.android().willCreateOrderMealCode(canteenId, stallId, orderDate, mealtimeType);
      if (CharSequenceUtil.isNotEmpty(mealCode)) {
         return this.orderCustomBusiness.android().didCreateOrderMealCode(canteenId, stallId, orderDate, mealtimeType, mealCode);
      } else {
         String prefix = null;
         if (OrderTypeEnum.isShopCategory(orderType)) {
            SupermarketInfo supermarketInfoById = this.supermarketApi.getSupermarketInfoById(canteenId);
            prefix = supermarketInfoById != null ? supermarketInfoById.getMealCode() : "";
         } else if (OrderTypeEnum.isCanteenCategory(orderType) && LeNumUtil.isValidId(stallId)) {
            AllocStall allocStall = this.allocStallApi.getAllocStall(stallId);
            if (allocStall != null) {
               prefix = OrderTypeEnum.isAndroidCategory(orderType) ? allocStall.getOffLineMealCodePrefix() : allocStall.getOnLineMealCodePrefix();
            }
         }

         mealCode = this.numUtil.getMealCode(prefix, canteenId, stallId, orderDate, mealtimeType);
         log.info("创建叫号码：{}", mealCode);
         return this.orderCustomBusiness.android().didCreateOrderMealCode(canteenId, stallId, orderDate, mealtimeType, mealCode);
      }
   }

   public void didUpdateDishesState(Long orderId, Integer dishesStateBeforeUpdated) {
      OrderInfo orderInfo = this.orderInfoService.getById(orderId);
      CustPayVO custInfo = this.orderModuleClient.custPayInfoQuery(CustPayInfoQueryParam.ofCustId(orderInfo.getCustId()));
      this.updateCallCacheIfNeed(OrderCallListVO.of(orderInfo, custInfo != null ? custInfo.getCustName() : null));
      if (!ObjectUtil.equal(dishesStateBeforeUpdated, orderInfo.getDishesState())) {
         OrderMessageSend.orderV3DishesStateUpdated(orderInfo, dishesStateBeforeUpdated);
      }

      this.orderCustomBusiness.android().didUpdateOrderDishesStateV2(orderInfo, dishesStateBeforeUpdated);
   }

   protected void updateCallCacheIfNeed(OrderCallListVO orderCallListVO) {
      if (orderCallListVO != null && LeNumUtil.isValidId(orderCallListVO.getStallId()) && !CharSequenceUtil.isEmpty(orderCallListVO.getMealCode())) {
         RLock lock = RedisUtil.getLock(OrderCacheConstants.orderCallCacheLockKey(orderCallListVO.getStallId(), orderCallListVO.getMealtimeType()));
         lock.lock(10L, TimeUnit.SECONDS);

         try {
            Object obj = RedisUtil.getObj(OrderCacheConstants.orderCallCacheKey(orderCallListVO.getStallId(), orderCallListVO.getMealtimeType()));
            Map orderCallMap;
            if (obj instanceof Map) {
               orderCallMap = (Map)obj;
            } else {
               orderCallMap = this.queryOrderCallMap(orderCallListVO.getStallId(), orderCallListVO.getMealtimeType());
            }

            if (!OrderStateOldEnum.MAKEING.getKey().equals(orderCallListVO.getOrdState()) && !OrderStateOldEnum.WAITTAKE.getKey().equals(orderCallListVO.getOrdState())) {
               orderCallMap.remove(orderCallListVO.getOrderId().toString());
            } else {
               orderCallMap.put(orderCallListVO.getOrderId().toString(), orderCallListVO);
            }

            RedisUtil.setObj(OrderCacheConstants.orderCallCacheKey(orderCallListVO.getStallId(), orderCallListVO.getMealtimeType()), orderCallMap, OrderCacheConstants.CALL_CACHE_SECONDS);
         } finally {
            try {
               if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                  lock.unlock();
               }
            } catch (Exception var10) {
               log.error("解锁异常", var10);
            }

         }

      }
   }

   protected Map<String, OrderCallListVO> queryOrderCallMap(Long stallId, Integer mealtimeType) {
      OrderSearchParam androidQueryDTO = new OrderSearchParam();
      androidQueryDTO.setStartDate(LocalDate.now());
      androidQueryDTO.setEndDate(LocalDate.now());
      androidQueryDTO.setOrderStateList(CollUtil.toList(new Integer[]{OrderStateEnum.PLACE.getKey()}));
      androidQueryDTO.setDishesStateList(CollUtil.toList(new Integer[]{DishesStateEnum.MAKING.getKey(), DishesStateEnum.WAIT_TAKE.getKey()}));
      androidQueryDTO.setMealtimeTypeList(CollUtil.toList(new Integer[]{mealtimeType}));
      androidQueryDTO.setStallIdList(CollUtil.toList(new Long[]{stallId}));
      if (LeNumUtil.isValidId(stallId)) {
         AllocStall allocStall = this.allocStallApi.getAllocStall(stallId);
         if (allocStall != null) {
            androidQueryDTO.setCanteenIdList(CollUtil.toList(new Long[]{allocStall.getCanteenId()}));
         }
      }

      OrderQueryHelper.initQueryParam(androidQueryDTO);
      List<OrderIdDateVO> orderIdDatePage = this.orderInfoService.queryOrderId(androidQueryDTO, (OrderUserPermissionDTO)null);
      List<OrderListAndroidVO> orderListAndroidVOS = this.orderInfoService.listOrderForAndroid((List)orderIdDatePage.stream().map(OrderIdDateVO::getId).collect(Collectors.toList()), (List)orderIdDatePage.stream().map(OrderIdDateVO::getOrderDate).collect(Collectors.toList()));
      return orderListAndroidVOS.stream().filter((s) -> {
         return !DishesStateEnum.ALREADY_TAKE.getKey().equals(s.getDishesState());
      }).map(OrderCallListVO::of).collect(Collectors.toMap((s) -> {
         return s.getOrderId().toString();
      }, Function.identity()));
   }

}
