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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.bonus.core.common.page.PageVO;
import com.bonus.core.device.api.DeviceApi;
import com.bonus.core.device.manage.dto.DeviceSearchDTO;
import com.bonus.core.device.manage.model.DeviceInfo;
import com.bonus.core.menu.api.MenuDishesApi;
import com.bonus.core.menu.utils.NutritionEntity;
import com.bonus.core.order.common.constants.CheckStateEnum;
import com.bonus.core.order.common.constants.DetailTypeEnum;
import com.bonus.core.order.common.constants.OrderTypeEnum;
import com.bonus.core.order.common.dto.RequestHeaderDTO;
import com.bonus.core.order.common.model.OrderDelivery;
import com.bonus.core.order.common.model.OrderRefund;
import com.bonus.core.order.common.query.OrderQueryHelper;
import com.bonus.core.order.common.service.*;
import com.bonus.core.order.common.vo.OrderIdDateVO;
import com.bonus.core.order.custom.OrderCustomBusiness;
import com.bonus.core.order.mobile.dto.OrderListMobileDTO;
import com.bonus.core.order.mobile.service.OrderInfoMobileBusiness;
import com.bonus.core.order.mobile.vo.OrderDetailMobileVO;
import com.bonus.core.order.mobile.vo.OrderInfoMobileVO;
import com.bonus.core.order.mobile.vo.OrderListMobileVO;
import com.bonus.core.order.mobile.vo.OrderNutrientInfoVO;
import com.bonus.core.order.utils.LeNumUtil;
import com.bonus.core.order.web.dto.OrderUserPermissionDTO;
import com.bonus.core.order.weight.service.MacPlateidBindSerialService;
import com.bonus.core.order.weight.model.MacPlateidBindSerial;
import com.bonus.core.order.weight.vo.RefundDetailStateVO;
import com.bonus.utils.AesEncryptUtil;
import com.bonus.core.menu.model.MenuDishesTypeModel;
import com.github.pagehelper.page.PageMethod;
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.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class OrderInfoMobileBusinessImpl implements OrderInfoMobileBusiness {
   private static final Logger log = LoggerFactory.getLogger(OrderInfoMobileBusinessImpl.class);
   @Lazy
   @Autowired
   protected OrderInfoService orderInfoService;
   @Lazy
   @Autowired
   protected OrderDeliveryService orderDeliveryService;
   @Lazy
   @Autowired
   protected OrderDetailService orderDetailService;
   @Lazy
   @Autowired
   protected OrderRefundService orderRefundService;
   @Lazy
   @Autowired
   protected OrderCustomBusiness orderCustomBusiness;
   @Lazy
   @Autowired
   protected DeviceApi deviceApi;
   @Lazy
   @Autowired
   protected MacPlateidBindSerialService macPlateidBindSerialService;
   @Lazy
   @Autowired
   protected AesEncryptUtil aesEncryptUtil;
   @Lazy
   @Autowired
   protected MenuDishesApi menuDishesApi;
   @Lazy
   @Autowired
   protected OrderRefundDetailService orderRefundDetailService;

   @Override
   public PageVO<OrderListMobileVO> orderList(OrderListMobileDTO orderListDTO, RequestHeaderDTO headerDTO) {
      orderListDTO.setCustId(this.getCustId(orderListDTO.getCustId(), headerDTO));
      if (orderListDTO.getCustId() == null) {
         return PageVO.empty();
      } else {
         OrderQueryHelper.initQueryDate(orderListDTO, -7, 7);
         OrderQueryHelper.initQueryParam(orderListDTO);
         PageMethod.startPage(orderListDTO.getCurrent().intValue(), orderListDTO.getSize().intValue());
         List<OrderIdDateVO> orderIdDatePage = this.orderInfoService.queryOrderId(orderListDTO.convertToOrderSearchParam(), (OrderUserPermissionDTO)null);
         List<OrderListMobileVO> records = this.orderInfoService.getOrderMobileList((List)orderIdDatePage.stream().map(OrderIdDateVO::getId).collect(Collectors.toList()), (List)orderIdDatePage.stream().map(OrderIdDateVO::getOrderDate).collect(Collectors.toList()));
         PageVO<OrderListMobileVO> orderPage = PageVO.of(orderIdDatePage, records);
         List<OrderListMobileVO> orderList = orderPage.getRecords();
         if (CollUtil.isEmpty(orderList)) {
            this.orderCustomBusiness.mobile().didQueryOrderList(orderListDTO, orderPage);
            return orderPage;
         } else {
            log.info("[移动端订单列表]查询订单详情：{}", orderList.size());
            List<Long> orderIdList = (List)orderList.stream().map(OrderListMobileVO::getOrderId).collect(Collectors.toList());
            List<LocalDate> dateList = (List)orderList.stream().map(OrderListMobileVO::getOrderDate).collect(Collectors.toList());
            List<OrderDetailMobileVO> orderDetailList = (List)this.orderDetailService.getOrderDetailList(orderIdList, dateList, (List<Integer>)null)
                    .stream().map(OrderDetailMobileVO::of).collect(Collectors.toList());
            this.orderDetailService.fillOrderDetailImage(orderDetailList);
            Map<Long, List<OrderDetailMobileVO>> orderDetailMap = (Map)orderDetailList.stream().collect(Collectors.groupingBy(OrderDetailMobileVO::getOrderId));
            Map<String, DeviceInfo> deviceMap = MapUtil.empty();
            List<String> snList = (List<String>)orderList.stream().map(OrderListMobileVO::getMachineSn).filter(CharSequenceUtil::isNotEmpty).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(snList)) {
               log.info("[移动端订单列表]查询设备信息：{}", snList.size());
               deviceMap = (Map)this.deviceApi.listInfo((new DeviceSearchDTO()).setDeviceSnList(snList)).stream().collect(Collectors.toMap(DeviceInfo::getDeviceSn, Function.identity()));
            }

            List<String> plateSerialNums = (List)orderList.stream().map(OrderListMobileVO::getPlateSerialNum).filter(CharSequenceUtil::isNotEmpty).collect(Collectors.toList());
            Map<String, String> platNumMap = this.getPlatNumMap(plateSerialNums);
            log.info("[移动端订单列表]查询退款信息：{}", orderIdList.size());
            Map<Long, List<OrderRefund>> orderRefundGroup = (Map)this.orderRefundService.listByOrderIds(orderIdList, (Integer)null, (Integer)null).stream().collect(Collectors.groupingBy(OrderRefund::getOrderId));
            Iterator var16 = orderList.iterator();

            while(var16.hasNext()) {
               OrderListMobileVO orderVO = (OrderListMobileVO)var16.next();
               List<OrderDetailMobileVO> detailMobileList = (List)orderDetailMap.getOrDefault(orderVO.getOrderId(), ListUtil.empty());
               List<OrderRefund> orderRefundList = (List)orderRefundGroup.getOrDefault(orderVO.getOrderId(), ListUtil.empty());
               orderVO.setOrderDetailSum(detailMobileList.size());
               orderVO.setOrderDetailList(detailMobileList);
               orderVO.fillDeviceInfo((DeviceInfo)deviceMap.get(orderVO.getMachineSn()));
               orderVO.setPlateNum((String)platNumMap.getOrDefault(orderVO.getPlateSerialNum(), ""));
               orderRefundList.stream().filter((s) -> {
                  return !CheckStateEnum.WAIT.getKey().equals(s.getCheckState());
               }).max(Comparator.comparing(OrderRefund::getOrderRefundId)).ifPresent((s) -> {
                  orderVO.setRefundTime(s.getCheckTime());
               });
               orderRefundList.stream().max(Comparator.comparing(OrderRefund::getOrderRefundId)).ifPresent((s) -> {
                  orderVO.setCheckState(s.getCheckState());
               });
            }

            this.orderCustomBusiness.mobile().didQueryOrderList(orderListDTO, orderPage);
            return orderPage;
         }
      }
   }

   protected Long getCustId(Long custId, RequestHeaderDTO headerDTO) {
      return ObjectUtil.isNotNull(custId) ? custId : headerDTO.getCustId();
   }

   public Map<String, String> getPlatNumMap(List<String> plateSerialNums) {
      return CollUtil.isEmpty(plateSerialNums) ? MapUtil.empty() : (Map)this.macPlateidBindSerialService.queryBindByPlateSerialNumList(plateSerialNums).stream().collect(Collectors.toMap(MacPlateidBindSerial::getPlateSerialNum, MacPlateidBindSerial::getPlateId, (k1, k2) -> {
         return k2;
      }));
   }

   @Override
   public OrderInfoMobileVO orderInfo(Long orderId) {
      OrderInfoMobileVO orderInfoVO = this.orderInfoService.getOrderInfoMobileByOrderId(orderId);
      if (ObjectUtil.isNull(orderInfoVO)) {
         return null;
      } else {
         List<OrderDetailMobileVO> detailMobileList = (List<OrderDetailMobileVO>)this.orderDetailService
                 .getOrderDetailList(orderId, orderInfoVO.getOrderDate())
                 .stream().map(OrderDetailMobileVO::of).collect(Collectors.toList());
         orderInfoVO.setOrderDetailList(detailMobileList);
         this.fillOrderInfoMobileDetail(orderInfoVO, detailMobileList);
         this.fillOrderDetailMobileCheckState(orderInfoVO, detailMobileList);
         this.fillWeightPlateNum(orderInfoVO);
         orderInfoVO = this.orderCustomBusiness.mobile().didQueryOrderInfo(orderInfoVO);
         return orderInfoVO;
      }
   }

   protected void fillOrderInfoMobileDetail(OrderInfoMobileVO orderInfoVO, List<OrderDetailMobileVO> detailMobileList) {
      log.info("[移动端订单详情]查询配送信息：{}", orderInfoVO.getOrderId());
      OrderDelivery deliveryInfo = this.orderDeliveryService.getByOrderId(orderInfoVO.getOrderId(), orderInfoVO.getOrderDate());
      if (ObjectUtil.isNotNull(deliveryInfo)) {
         orderInfoVO.setConsigneeName(deliveryInfo.getConsigneeName());
         orderInfoVO.setConsigneeMobile(AesEncryptUtil.aesEncrypt(deliveryInfo.getConsigneeMobile()));
         orderInfoVO.setConsigneeAddress(deliveryInfo.getConsigneeAddress());
         orderInfoVO.setDeliveryTime(deliveryInfo.getDeliveryTime());
         orderInfoVO.setDeliveryCode(deliveryInfo.getDeliveryCode());
      }

      if (OrderTypeEnum.BUFFET.getKey().equals(orderInfoVO.getOrderType()) && CollUtil.isNotEmpty(detailMobileList)) {
         log.info("[移动端订单详情]查询营养信息：{}", orderInfoVO.getOrderId());
         Map<Long, Double> dishesQuantityMap = (Map)detailMobileList.stream()
                 .collect(Collectors.toMap(OrderDetailMobileVO::getGoodsDishesId, OrderDetailMobileVO::totalGram, Double::sum));
         orderInfoVO.fillNutrientInfo(this.getNutrientInfo(dishesQuantityMap));
      }

      if (CharSequenceUtil.isNotEmpty(orderInfoVO.getMachineSn())) {
         log.info("[移动端订单详情]查询设备信息：{}", orderInfoVO.getMachineSn());
         DeviceInfo deviceBySn = this.deviceApi.getBySn(orderInfoVO.getMachineSn());
         orderInfoVO.fillDeviceInfo(deviceBySn);
      }

      log.info("[移动端订单详情]查询菜品分类名称：{}", orderInfoVO.getOrderId());
      List<Long> dishesIds = (List)detailMobileList.stream().filter((s) -> {
         return DetailTypeEnum.isDishesCategory(s.getDetailType());
      }).map(OrderDetailMobileVO::getGoodsDishesId).filter(LeNumUtil::isValidId).collect(Collectors.toList());
      Map<Long, String> dishesTypeNameMap = (Map)this.menuDishesApi.getDishesTypeName(dishesIds).stream()
              .collect(Collectors.toMap(MenuDishesTypeModel::getDishesId, MenuDishesTypeModel::getTypeName, (k1, k2) -> {
         return k2;
      }));
      detailMobileList.forEach((s) -> {
         s.setGoodsDishesTypeName((String)dishesTypeNameMap.get(s.getGoodsDishesId()));
      });
      this.orderDetailService.fillOrderDetailImage(detailMobileList);
   }

   public OrderNutrientInfoVO getNutrientInfo(Map<Long, Double> dishesQuantityMap) {
      NutritionEntity nutrientInfo = this.menuDishesApi.getNutrientInfo(dishesQuantityMap);
      return OrderNutrientInfoVO.of(nutrientInfo);
   }

   protected void fillOrderDetailMobileCheckState(OrderInfoMobileVO orderInfoVO, List<OrderDetailMobileVO> detailMobileList) {
      if (orderInfoVO != null && !CollUtil.isEmpty(detailMobileList)) {
         log.info("[移动端订单详情]查询退款审核状态：{}", orderInfoVO.getOrderId());
         List<RefundDetailStateVO> refundDetailStateVOList = this.orderRefundDetailService.listRefundDetailState(CharSequenceUtil.isEmpty(orderInfoVO.getMacOrderId()) ? orderInfoVO.getOrderId() : null, CharSequenceUtil.isNotEmpty(orderInfoVO.getMacOrderId()) ? orderInfoVO.getMacOrderId() : null);
         if (!CollUtil.isEmpty(refundDetailStateVOList)) {
            Iterator var4 = detailMobileList.iterator();

            while(var4.hasNext()) {
               OrderDetailMobileVO orderDetailMobileVO = (OrderDetailMobileVO)var4.next();
               refundDetailStateVOList.stream().filter((s) -> {
                  return orderDetailMobileVO.getDetailId().equals(s.getMenuId());
               }).max(Comparator.comparing(RefundDetailStateVO::getOrderRefundId)).ifPresent((s) -> {
                  orderDetailMobileVO.setCheckState(s.getCheckState());
               });
            }

            refundDetailStateVOList.stream().filter((s) -> {
               return orderInfoVO.getOrderId().equals(s.getOrderId());
            }).filter((s) -> {
               return s.getFeeAmount().compareTo(BigDecimal.ZERO) > 0;
            }).max(Comparator.comparing(RefundDetailStateVO::getOrderRefundId)).ifPresent((s) -> {
               orderInfoVO.setCheckState(s.getCheckState());
               orderInfoVO.setRefundFeeAmount(s.getFeeAmount());
            });
         }
      }
   }

   public void fillWeightPlateNum(OrderInfoMobileVO orderInfoMobileVO) {
      if (CharSequenceUtil.isNotBlank(orderInfoMobileVO.getPlateSerialNum())) {
         List<MacPlateidBindSerial> plates = this.macPlateidBindSerialService.queryBindByPlateSerialNumList(CollUtil.toList(new String[]{orderInfoMobileVO.getPlateSerialNum()}));
         if (CollUtil.isNotEmpty(plates)) {
            orderInfoMobileVO.setPlateNum(((MacPlateidBindSerial)plates.get(0)).getPlateId());
         }
      }

   }

}
