package com.bonus.canteen.core.allocation.canteen.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.canteen.core.allocation.canteen.dto.AllocCanteenModifyDTO;
import com.bonus.canteen.core.allocation.canteen.dto.ModifyCanteenIfReserveDTO;
import com.bonus.canteen.core.allocation.canteen.mapper.AllocAreaMapper;
import com.bonus.canteen.core.allocation.canteen.param.AllocCanteenStallPageParam;
import com.bonus.canteen.core.allocation.canteen.vo.AllocCanteenVO;
import com.bonus.canteen.core.common.enums.AllocBusinessStateEnum;
import com.bonus.canteen.core.common.utils.AesEncryptUtil;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.houqin.constant.LeConstants;
import com.bonus.canteen.core.allocation.api.AllocPayMetadataApi;
import com.bonus.canteen.core.allocation.canteen.mapper.AllocCanteenMapper;
import com.bonus.canteen.core.allocation.canteen.mapper.AllocStallMapper;
import com.bonus.canteen.core.allocation.canteen.model.AllocCanteen;
import com.bonus.canteen.core.allocation.canteen.model.AllocStall;
import com.bonus.canteen.core.allocation.canteen.service.AllocAreaService;
import com.bonus.canteen.core.allocation.canteen.service.AllocCanteenService;
import com.bonus.canteen.core.allocation.canteen.vo.AllocCanteenStallVO;
import com.bonus.canteen.core.common.enums.AllocCanteenTypeEnum;
import com.bonus.canteen.core.common.redis.RedisUtil;
import com.bonus.canteen.core.common.utils.TenantContextHolder;
import com.bonus.canteen.core.menu.vo.AppletReserveCanteenVO;
import com.bonus.canteen.core.menu.vo.AppletReserveStallVO;
import com.bonus.common.houqin.i18n.I18n;
import com.bonus.common.houqin.utils.LeBeanUtil;
import com.bonus.canteen.core.order.utils.LeNumUtil;
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.util.*;
import java.util.stream.Collectors;

@Service
public class AllocCanteenServiceImpl extends ServiceImpl<AllocCanteenMapper, AllocCanteen> implements AllocCanteenService {
   private static final Logger log = LoggerFactory.getLogger(AllocCanteenServiceImpl.class);
   private static final String CACHE_PREFIX = "yst:";
   private static final String CACHE_KEY = "alloc-canteen";
   private static final long CACHE_SECONDS = 3600L;
   @Resource
   @Lazy
   private AllocPayMetadataApi allocPayMetadataApi;
   @Autowired
   @Lazy
   private AllocAreaService allocAreaService;
   @Resource
   private AllocStallMapper allocStallMapper;
   @Resource
   private AesEncryptUtil aesEncryptUtil;
   @Resource
   private AllocAreaMapper allocAreaMapper;

   @Override
   public List<Integer> listAvailPayTypeForApp(Long canteenId) {
      return this.allocPayMetadataApi.supportPayChannels(canteenId);
   }

   @Override
   public List<Long> getCanteenIdListByAreaIdList(List<Long> areaIdList) {
      if (CollUtil.isEmpty(areaIdList)) {
         return new ArrayList();
      } else {
         List<Long> allAreaIdList = new ArrayList();
         Iterator var3 = areaIdList.iterator();

         while(var3.hasNext()) {
            Long areaId = (Long)var3.next();
            allAreaIdList.addAll(this.allocAreaService.getAllChildrenId(areaId));
         }

         allAreaIdList = new ArrayList(new HashSet(allAreaIdList));
         return ((AllocCanteenMapper)this.baseMapper).getCanteenIdListByAreaIdList(allAreaIdList);
      }
   }

   @Override
   public List<AllocCanteenStallVO> listAllCanteenStall() {
      List<AllocCanteenStallVO> canteenList = ((AllocCanteenMapper)this.baseMapper).listAllCanteenStall(LeConstants.COMMON_NO, AllocCanteenTypeEnum.CANTEEN.getKey());
      if (CollUtil.isEmpty(canteenList)) {
         return canteenList;
      } else {
         canteenList.forEach((canteen) -> {
            canteen.setStallList(this.allocStallMapper.listAllCanteenStall(canteen.getCanteenId()));
         });
         return canteenList;
      }
   }

   @Override
   public void checkAndDelReserveCanteen(List<AppletReserveCanteenVO> reserveCanteenList) {
      List<Long> canteenIdList = new ArrayList();
      List<Long> stallIdList = new ArrayList();
      Iterator var4 = reserveCanteenList.iterator();

      while(true) {
         AppletReserveCanteenVO reserveCanteen;
         do {
            if (!var4.hasNext()) {
               List<AllocCanteen> allocCanteenList = this.list((Wrapper<AllocCanteen>) Wrappers.lambdaQuery(AllocCanteen.class).select(AllocCanteen::getCanteenId, AllocCanteen::getIfReserve).in(AllocCanteen::getCanteenId, canteenIdList));
               Map<Long, Integer> allocCanteenMap = (Map)allocCanteenList.stream().collect(Collectors.toMap(AllocCanteen::getCanteenId, AllocCanteen::getIfReserve));
               Map<Long, Integer> allocStallMap = new HashMap();
               if (CollUtil.isNotEmpty(stallIdList)) {
                  List<AllocStall> allocStallList = this.allocStallMapper.selectList((Wrapper<AllocStall>)Wrappers.lambdaQuery(AllocStall.class).select(AllocStall::getStallId, AllocStall::getIfReserve).in(AllocStall::getStallId, stallIdList));
                  allocStallMap = (Map)allocStallList.stream().collect(Collectors.toMap(AllocStall::getStallId, AllocStall::getIfReserve));
               }

               Iterator<AppletReserveCanteenVO> canteenIterator = reserveCanteenList.iterator();

               while(true) {
                  while(canteenIterator.hasNext()) {
                     AppletReserveCanteenVO reserveCanteenVO = (AppletReserveCanteenVO)canteenIterator.next();
                     Integer canteenIfReserve = (Integer)allocCanteenMap.get(reserveCanteenVO.getCanteenId());
                     if (!LeConstants.COMMON_YES.equals(canteenIfReserve)) {
                        canteenIterator.remove();
                     } else if (CollUtil.isNotEmpty(reserveCanteenVO.getStallList())) {
                        Iterator<AppletReserveStallVO> stallIterator = reserveCanteenVO.getStallList().iterator();

                        while(stallIterator.hasNext()) {
                           AppletReserveStallVO reserveStallVO = (AppletReserveStallVO)stallIterator.next();
                           Integer stallIfReserve = (Integer)((Map)allocStallMap).get(reserveStallVO.getStallId());
                           if (!LeConstants.COMMON_YES.equals(stallIfReserve)) {
                              stallIterator.remove();
                           }
                        }
                     }
                  }

                  return;
               }
            }

            reserveCanteen = (AppletReserveCanteenVO)var4.next();
            canteenIdList.add(reserveCanteen.getCanteenId());
         } while(!CollUtil.isNotEmpty(reserveCanteen.getStallList()));

         Iterator var6 = reserveCanteen.getStallList().iterator();

         while(var6.hasNext()) {
            AppletReserveStallVO reserveStall = (AppletReserveStallVO)var6.next();
            stallIdList.add(reserveStall.getStallId());
         }
      }
   }

   public AllocCanteen getAllocCanteenCache(Long canteenId) {
      if (ObjectUtil.isNull(canteenId)) {
         return null;
      } else {
         String cacheKey = this.getCacheKey(canteenId);
         String allocCanteenStr = RedisUtil.getString(cacheKey);
         if (CharSequenceUtil.isNotBlank(allocCanteenStr)) {
            return (AllocCanteen) JSONUtil.toBean(allocCanteenStr, AllocCanteen.class);
         } else {
            AllocCanteen allocCanteen = (AllocCanteen)this.getOne((Wrapper)Wrappers.lambdaQuery(AllocCanteen.class).eq(AllocCanteen::getCanteenId, canteenId));
            allocCanteenStr = JSONUtil.toJsonStr(allocCanteen);
            RedisUtil.setString(cacheKey, allocCanteenStr, 3600L);
            return allocCanteen;
         }
      }
   }

   private String getCacheKey(Long canteenId) {
      Long var10000 = TenantContextHolder.getTenantId();
      return "yst:" + var10000 + ":alloc-canteen:" + canteenId;
   }

   public Page<AllocCanteenVO> pageCanteen(AllocCanteenStallPageParam param) {
      param.setCanteenName(LeBeanUtil.fieldLikeHandle(param.getCanteenName()));
      param.setIfDel(LeConstants.COMMON_NO);
      param.setCanteenType(AllocCanteenTypeEnum.CANTEEN.getKey());
      Page<AllocCanteenVO> page = new Page(param.getCurrent(), param.getSize());
      if (ObjectUtil.isNotNull(param.getAreaId())) {
         param.setAreaIdList(this.allocAreaService.getAllChildrenId(param.getAreaId()));
      }

      page = this.baseMapper.pageCanteen(page, param);
      Iterator var3 = page.getRecords().iterator();

      while(var3.hasNext()) {
         AllocCanteenVO canteenVO = (AllocCanteenVO)var3.next();
         canteenVO.setContactTel(this.aesEncryptUtil.aesEncrypt(canteenVO.getContactTel()));
      }

      return page;
   }

   public void checkCanteenNameExist(String canteenName, Long canteenId) {
      boolean flag = this.count((Wrappers.lambdaQuery(AllocCanteen.class).eq(AllocCanteen::getCanteenName, canteenName))
              .ne(ObjectUtil.isNotNull(canteenId), AllocCanteen::getCanteenId, canteenId)
              .eq(AllocCanteen::getIfDel, LeConstants.COMMON_NO)) > 0L;
      if (flag) {
         throw new ServiceException(I18n.getMessage("alloc_canteen_name_exist", new Object[0]));
      }
   }

   public void saveCanteen(AllocCanteen allocCanteen) {
      this.save(allocCanteen);
      this.clearCache();
   }
   private void clearCache() {
      RedisUtil.deleteByPattern("yst:" + TenantContextHolder.getTenantId() + ":alloc-canteen:*");
   }

   public void correctCanteenNum() {
      List<AllocCanteen> canteenList = ((AllocCanteenMapper)this.baseMapper).listCanteenNumBlank();
      if (!CollUtil.isEmpty(canteenList)) {
         canteenList.forEach((canteen) -> {
            String canteenNum = this.getLatestCanteenNum(canteen.getAreaId());
            canteenNum = CharSequenceUtil.replaceIgnoreCase(canteenNum, "null", "01");
            ((AllocCanteenMapper)this.baseMapper).updateNumById(canteenNum, canteen.getCanteenId());
         });
      }
   }

   public String getLatestCanteenNum(Long superId) {
      String superNum = this.allocAreaMapper.getAreaNumById(superId);
      if (CharSequenceUtil.isBlank(superNum)) {
         superNum = "01";
      }

      String canteenNum = ((AllocCanteenMapper)this.baseMapper).getLatestCanteenNum(superId);
      return LeNumUtil.getCanteenNum(superNum, canteenNum, true);
   }

   public void modifyByCanteenId(AllocCanteenModifyDTO canteenModifyDTO, Long canteenId) {
      ((AllocCanteenMapper)this.baseMapper).updateByCanteenId(canteenModifyDTO, canteenId);
      this.clearCache();
   }

   public void deleteCanteen(Long canteenId) {
      this.update(Wrappers.lambdaUpdate(AllocCanteen.class).set(AllocCanteen::getIfDel, LeConstants.COMMON_YES)
              .eq(AllocCanteen::getCanteenId, canteenId));
      this.clearCache();
   }

   public void modifyCanteenIfReserve(ModifyCanteenIfReserveDTO reserveDTO) {
      this.update(Wrappers.lambdaUpdate(AllocCanteen.class).set(AllocCanteen::getIfReserve, reserveDTO.getIfReserve())
              .eq(AllocCanteen::getCanteenId, reserveDTO.getCanteenId()));
      this.clearCache();
   }

   public void modifyBusinessState(Long canteenId, Integer businessState) {
      this.update(Wrappers.lambdaUpdate(AllocCanteen.class).set(AllocCanteen::getBusinessState, businessState)
              .eq(AllocCanteen::getCanteenId, canteenId));
      this.clearCache();
   }

   public Integer checkCanteenRest(Long canteenId) {
      boolean flag = this.allocStallMapper.selectCount(Wrappers.lambdaQuery(AllocStall.class)
              .eq(AllocStall::getCanteenId, canteenId).eq(AllocStall::getBusinessState,
                      AllocBusinessStateEnum.OPEN.getKey()).eq(AllocStall::getIfDel, LeConstants.COMMON_NO)) > 0L;
      return flag ? LeConstants.COMMON_YES : LeConstants.COMMON_NO;
   }

   public AllocCanteen checkCanteenIdExist(Long canteenId) {
      AllocCanteen allocCanteen = this.getOne(Wrappers.lambdaQuery(AllocCanteen.class)
              .eq(AllocCanteen::getCanteenId, canteenId));
      if (ObjectUtil.isNull(allocCanteen)) {
         throw new ServiceException("没有查询到对应食堂信息");
      } else {
         return allocCanteen;
      }
   }

}
