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.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.canteen.core.allocation.api.AllocHolidayApi;
import com.bonus.canteen.core.allocation.api.AllocOrderMetadataApi;
import com.bonus.canteen.core.allocation.canteen.dto.AllocCanteenOrderDTO;
import com.bonus.canteen.core.allocation.canteen.dto.AllocMobileCanteenQueryDTO;
import com.bonus.canteen.core.allocation.canteen.dto.AllocStallModifyDTO;
import com.bonus.canteen.core.allocation.canteen.dto.ModifyStallIfReserveDTO;
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.AllocStall;
import com.bonus.canteen.core.allocation.canteen.param.AllocCanteenStallPageParam;
import com.bonus.canteen.core.allocation.canteen.param.AllocCanteenStallParam;
import com.bonus.canteen.core.allocation.canteen.service.AllocAreaService;
import com.bonus.canteen.core.allocation.canteen.service.AllocStallService;
import com.bonus.canteen.core.allocation.canteen.vo.AllocStallAuthVO;
import com.bonus.canteen.core.allocation.canteen.vo.AllocStallVO;
import com.bonus.canteen.core.common.enums.AllocStallTypeEnum;
import com.bonus.canteen.core.common.redis.RedisUtil;
import com.bonus.canteen.core.common.utils.AesEncryptUtil;
import com.bonus.canteen.core.common.utils.TenantContextHolder;
import com.bonus.canteen.core.order.utils.LeNumUtil;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.houqin.constant.LeConstants;
import com.bonus.common.houqin.i18n.I18n;
import com.bonus.common.houqin.utils.LeBeanUtil;
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.time.LocalDate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Service
public class AllocStallServiceImpl extends ServiceImpl<AllocStallMapper, AllocStall> implements AllocStallService{
   private static final Logger log = LoggerFactory.getLogger(AllocStallServiceImpl.class);
   private static final String CACHE_PREFIX = "yst:";
   private static final String CACHE_KEY = "alloc-stall";
   private static final long CACHE_SECONDS = 3600L;

   @Autowired
   @Lazy
   private AllocOrderMetadataApi allocOrderMetadataApi;

   @Autowired
   @Lazy
   private AllocHolidayApi allocHolidayApi;

   @Autowired
   @Lazy
   private AllocAreaService allocAreaService;

   @Resource
   private AesEncryptUtil aesEncryptUtil;

   @Resource
   private AllocCanteenMapper allocCanteenMapper;

   @Override
   public AllocStall getAllocStallCache(Long stallId) {
      if (ObjectUtil.isNull(stallId)) {
         return null;
      } else {
         String cacheKey = this.getCacheKey(stallId);
         String allocStallStr = RedisUtil.getString(cacheKey);
         if (CharSequenceUtil.isNotBlank(allocStallStr)) {
            return (AllocStall)JSONUtil.toBean(allocStallStr, AllocStall.class);
         } else {
            AllocStall allocStall = this.getOne(new LambdaQueryWrapper<AllocStall>().eq(AllocStall::getStallId, stallId));
            allocStallStr = JSONUtil.toJsonStr(allocStall);
            RedisUtil.setString(cacheKey, allocStallStr, 3600L);
            return allocStall;
         }
      }
   }

   @Override
   public List<LocalDate> listReserveDate(AllocMobileCanteenQueryDTO queryDTO) {
      AllocCanteenOrderDTO allocCanteenOrderDTO = this.allocOrderMetadataApi.queryAvailableOrder(queryDTO.getCanteenId(), queryDTO.getStallId());
      String ifReserveSkipHoliday = allocCanteenOrderDTO.getIfReserveSkipHoliday();
      Integer reserveLimitDayNum = Integer.parseInt(allocCanteenOrderDTO.getReserveLimitDay());
      return this.listMatchData(ifReserveSkipHoliday, reserveLimitDayNum, allocCanteenOrderDTO.getIfAllowReserveToday());
   }

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

   private List<LocalDate> listMatchData(String skipFlagStr, Integer limitNum, String ifAllowReserveToday) {
      log.info(String.format("查询日期,是否调过节假日:%s,天数:%d", skipFlagStr, limitNum));
      List<LocalDate> reserveDateList = new ArrayList();
      LocalDate startDate;
      if ("1".equals(ifAllowReserveToday)) {
         log.info("允许预定当天");
         startDate = LocalDate.now();
      } else {
         log.info("不允许预定当天");
         startDate = LocalDate.now().plusDays(1L);
      }

      if ("2".equals(skipFlagStr)) {
         for(int i = 0; i < limitNum; ++i) {
            reserveDateList.add(startDate.plusDays((long)i));
         }
      } else {
         List<LocalDate> holidayList = this.allocHolidayApi.getHolidayList();

         for(int i = 0; i < limitNum; ++i) {
            LocalDate reserveDate = startDate.plusDays((long)i);
            boolean skipFlag = false;
            Iterator var10 = holidayList.iterator();

            while(var10.hasNext()) {
               LocalDate holiday = (LocalDate)var10.next();
               if (reserveDate.isEqual(holiday)) {
                  skipFlag = true;
                  limitNum = limitNum + 1;
               }
            }

            if (!skipFlag) {
               reserveDateList.add(reserveDate);
            }
         }
      }

      return reserveDateList;
   }

   public boolean checkCanteenStallRelation(Long canteenId) {
      long count = this.count(Wrappers.lambdaQuery(AllocStall.class).eq(AllocStall::getCanteenId, canteenId)
              .eq(AllocStall::getIfDel, LeConstants.COMMON_NO));
      return count > 0L;
   }

   public void modifyBusinessState(Long stallId, Integer businessState) {
      this.update(Wrappers.lambdaUpdate(AllocStall.class).set(AllocStall::getBusinessState, businessState)
              .eq(AllocStall::getStallId, stallId));
      this.clearCache();
   }

   private void clearCache() {
      RedisUtil.deleteByPattern("yst:" + TenantContextHolder.getTenantId() + ":alloc-stall:*");
   }

   public Page<AllocStallVO> pageStall(AllocCanteenStallPageParam param) {
      param.setStallName(LeBeanUtil.fieldLikeHandle(param.getStallName()));
      param.setStallType(AllocStallTypeEnum.STALL.getKey());
      param.setIfDel(LeConstants.COMMON_NO);
      Page<AllocStallVO> page = new Page(param.getCurrent(), param.getSize());
      if (ObjectUtil.isNotNull(param.getAreaId())) {
         param.setAreaIdList(this.allocAreaService.getAllChildrenId(param.getAreaId()));
      }

      page = this.baseMapper.pageStall(page, param);
      if (CollUtil.isEmpty(page.getRecords())) {
         return page;
      } else {
         Iterator var3 = page.getRecords().iterator();

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

         return page;
      }
   }

   public void checkStallNameExist(String stallName, Long stallId) {
      boolean flag = this.count(Wrappers.lambdaQuery(AllocStall.class).eq(AllocStall::getStallName, stallName)
              .eq(AllocStall::getStallType, AllocStallTypeEnum.STALL.getKey())
              .ne(ObjectUtil.isNotNull(stallId), AllocStall::getStallId, stallId)
              .eq(AllocStall::getIfDel, LeConstants.COMMON_NO)) > 0L;
      if (flag) {
         throw new ServiceException(I18n.getMessage("alloc_stall_name_exist", new Object[0]));
      }
   }

   public void saveStall(AllocStall allocStall) {
      this.save(allocStall);
      this.clearCache();
   }

   public void correctStallNum() {
      List<AllocStall> stallList = ((AllocStallMapper)this.baseMapper).listStallNumBlank();
      if (!CollUtil.isEmpty(stallList)) {
         stallList.forEach((stall) -> {
            String stallNum = this.getLatestStallNum(stall.getCanteenId());
            stallNum = CharSequenceUtil.replaceIgnoreCase(stallNum, "null", "01");
            ((AllocStallMapper)this.baseMapper).updateNumById(stallNum, stall.getStallId());
         });
      }
   }

   public String getLatestStallNum(Long superId) {
      String superNum = this.allocCanteenMapper.getCanteenNumById(superId);
      if (CharSequenceUtil.isBlank(superNum)) {
         superNum = "01";
      }

      String stallNum = ((AllocStallMapper)this.baseMapper).getLatestStallNum(superId);
      return LeNumUtil.getCanteenNum(superNum, stallNum, true);
   }

   public void modifyByStallId(AllocStallModifyDTO stallModifyDTO, Long stallId) {
      ((AllocStallMapper)this.baseMapper).updateByStallId(stallModifyDTO, stallId);
      this.clearCache();
   }

   public void deleteStall(Long stallId) {
      this.update(Wrappers.lambdaUpdate(AllocStall.class).set(AllocStall::getIfDel, LeConstants.COMMON_YES)
              .eq(AllocStall::getStallId, stallId));
      this.clearCache();
   }

   public void modifyStallIfReserve(ModifyStallIfReserveDTO reserveDTO) {
      if (LeConstants.COMMON_YES.equals(reserveDTO.getIfReserve())) {
         boolean openCheck = LeConstants.COMMON_NO.equals(this.allocCanteenMapper.getIfReserve(reserveDTO.getCanteenId()));
         if (openCheck) {
            throw new ServiceException(I18n.getMessage("alloc_stall_reserve_check", new Object[0]));
         }
      }

      this.update(Wrappers.lambdaUpdate(AllocStall.class).set(AllocStall::getIfReserve, reserveDTO.getIfReserve()).eq(AllocStall::getStallId, reserveDTO.getStallId()));
      this.clearCache();
   }

   public List<AllocStallAuthVO> listMultipleAuthStall(AllocCanteenStallParam param) {
      return ((AllocStallMapper)this.baseMapper).listAuthStall(param.getCanteenIdList());
   }
}
