package com.bonus.canteen.core.supply.purchase.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
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.bonus.canteen.core.menu.domain.MenuMaterial;
import com.bonus.canteen.core.menu.enums.RoleCodeV2Enum;
import com.bonus.canteen.core.menu.mapper.MenuMaterialMapper;
import com.bonus.canteen.core.supply.purchase.constants.DrpApproveStatusEnum;
import com.bonus.canteen.core.supply.purchase.constants.DrpCommitStatusEnum;
import com.bonus.canteen.core.supply.purchase.constants.DrpContractStatusEnum;
import com.bonus.canteen.core.supply.purchase.constants.DrpMaterialPriceTypeEnum;
import com.bonus.canteen.core.supply.purchase.domain.bo.DrpContractDetailCommitDTO;
import com.bonus.canteen.core.supply.purchase.domain.bo.DrpMaterialLatestPriceDTO;
import com.bonus.canteen.core.supply.purchase.domain.bo.DrpProcurementContract;
import com.bonus.canteen.core.supply.purchase.domain.bo.DrpProcurementContractDetail;
import com.bonus.canteen.core.supply.purchase.domain.param.DrpContractCommitDTO;
import com.bonus.canteen.core.supply.purchase.domain.param.DrpContractPageDTO;
import com.bonus.canteen.core.supply.purchase.domain.vo.DrpContractDetailVO;
import com.bonus.canteen.core.supply.purchase.domain.vo.DrpContractPageVO;
import com.bonus.canteen.core.supply.purchase.mapper.DrpProcurementContractDetailMapper;
import com.bonus.canteen.core.supply.purchase.mapper.DrpProcurementContractMapper;
import com.bonus.canteen.core.supply.purchase.service.DrpMaterialLatestPriceService;
import com.bonus.canteen.core.supply.purchase.service.DrpProcurementContractService;
import com.bonus.canteen.core.supply.purchase.utils.CustomIdGenerateUtil;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.houqin.constant.DelFlagEnum;
import com.bonus.common.houqin.i18n.I18n;
import com.bonus.common.houqin.utils.LeBeanUtil;
import com.bonus.common.houqin.utils.id.Id;
import com.bonus.common.security.utils.SecurityUtils;
import com.github.pagehelper.page.PageMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.invoke.SerializedLambda;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class DrpProcurementContractServiceImpl implements DrpProcurementContractService {
   @Autowired
   @Lazy
   private DrpProcurementContractMapper drpProcurementContractMapper;
   @Autowired
   @Lazy
   private DrpProcurementContractDetailMapper drpProcurementContractDetailMapper;
   @Autowired
   @Lazy
   private MenuMaterialMapper menuMaterialMapper;
   @Autowired
   @Lazy
   private DrpMaterialLatestPriceService drpMaterialLatestPriceService;

   @Transactional(
      rollbackFor = {Exception.class}
   )
   public String commit(DrpContractCommitDTO content) {
      DrpProcurementContract check = this.drpProcurementContractMapper.getBySupplierId(content.getSupplierId());
      if (check != null) {
         throw new ServiceException("该供应商已存在有效合同！");
      } else {
         BigDecimal totalNum = content.getDetailList().stream().map(DrpContractDetailCommitDTO::getOrderNum).reduce(BigDecimal.ZERO, BigDecimal::add);
         List<MenuMaterial> menuMaterials = this.menuMaterialMapper.selectList(Wrappers.lambdaQuery(MenuMaterial.class).in(MenuMaterial::getMaterialId, content.getDetailList().stream().map(DrpContractDetailCommitDTO::getMaterialId).collect(Collectors.toList())).select(MenuMaterial::getCategoryId));
         Long categoryNum = menuMaterials.stream().map(MenuMaterial::getCategoryId).distinct().count();
         DrpProcurementContract drpProcurementContract;
         if (CharSequenceUtil.isEmpty(content.getContractId())) {
            String contractId = CustomIdGenerateUtil.generateContractId();
            drpProcurementContract = new DrpProcurementContract();
            BeanUtil.copyProperties(content, drpProcurementContract, new String[0]);
            drpProcurementContract.setContractStatus(DrpContractStatusEnum.WAIT_EFFECT.key());
            drpProcurementContract.setApproveStatus(DrpApproveStatusEnum.WAIT_APPROVE.key());
            drpProcurementContract.setDelFlag(DelFlagEnum.DEL_FALSE.key());
            drpProcurementContract.setContractId(contractId);
            drpProcurementContract.setTotalNum(totalNum);
            drpProcurementContract.setCategoryNum(Math.toIntExact(categoryNum));
            drpProcurementContract.setContractAttachment(JSONObject.toJSONString(content.getAttachmentDTOList()));
            this.drpProcurementContractMapper.insert(drpProcurementContract);
         } else {
            drpProcurementContract = (DrpProcurementContract)this.drpProcurementContractMapper.selectById(content.getContractId());
            BeanUtil.copyProperties(content, drpProcurementContract);
            drpProcurementContract.setContractStatus(DrpContractStatusEnum.WAIT_EFFECT.key());
            drpProcurementContract.setApproveStatus(DrpApproveStatusEnum.WAIT_APPROVE.key());
            drpProcurementContract.setDelFlag(DelFlagEnum.DEL_FALSE.key());
            drpProcurementContract.setTotalNum(totalNum);
            drpProcurementContract.setCategoryNum(Math.toIntExact(categoryNum));
            drpProcurementContract.setContractAttachment(JSONObject.toJSONString(content.getAttachmentDTOList()));
            this.drpProcurementContractMapper.updateById(drpProcurementContract);
            this.drpProcurementContractDetailMapper.delete(Wrappers.lambdaQuery(DrpProcurementContractDetail.class).eq(DrpProcurementContractDetail::getContractId, content.getContractId()));
         }

         if (CollUtil.isNotEmpty(content.getDetailList())) {
            Iterator var10 = content.getDetailList().iterator();

            while(var10.hasNext()) {
               DrpContractDetailCommitDTO detail = (DrpContractDetailCommitDTO)var10.next();
               DrpProcurementContractDetail drpProcurementContractDetail = new DrpProcurementContractDetail();
               BeanUtil.copyProperties(detail, drpProcurementContractDetail, new String[0]);
               drpProcurementContractDetail.setContractId(drpProcurementContract.getContractId());
               drpProcurementContractDetail.setContractDetailId(Id.next());
               this.drpProcurementContractDetailMapper.insert(drpProcurementContractDetail);
            }
         }

         Optional.ofNullable(content.getCommitStatus()).filter((status) -> {
            return status.equals(DrpCommitStatusEnum.COMMIT.key());
         }).ifPresent((status) -> {
            this.initiationApproval(drpProcurementContract, content.getDetailList());
         });
         return drpProcurementContract.getContractId();
      }
   }

   protected void initiationApproval(DrpProcurementContract drpProcurementContract, List<DrpContractDetailCommitDTO> detailList) {
      String userName = SecurityUtils.getUsername();
      this.drpProcurementContractMapper.update(null, (((((Wrappers.lambdaUpdate(DrpProcurementContract.class).set(DrpProcurementContract::getApproveStatus, DrpApproveStatusEnum.AGREE_APPROVE.key())).set(drpProcurementContract.getContractStartTime().isBefore(LocalDateTime.now()), DrpProcurementContract::getContractStatus, DrpContractStatusEnum.IN_PROGRESS.key())).set(drpProcurementContract.getContractEndTime().isBefore(LocalDateTime.now()), DrpProcurementContract::getContractStatus, DrpContractStatusEnum.EXPIRED.key())).set(DrpProcurementContract::getApproveBy, userName)).set(DrpProcurementContract::getApproveTime, LocalDateTime.now())).eq(DrpProcurementContract::getContractId, drpProcurementContract.getContractId()));
      (detailList.stream().collect(Collectors.toMap(DrpContractDetailCommitDTO::getMaterialId, Function.identity(), (k1, k2) -> {
         return k1;
      }))).values().forEach((detail) -> {
         this.drpMaterialLatestPriceService.addMaterialLatestPrice(DrpMaterialLatestPriceDTO.builder().materialId(detail.getMaterialId()).unitId(detail.getUnitId()).priceType(DrpMaterialPriceTypeEnum.MATERIAL_CONTRACT.key()).latestPrice(detail.getSinglePrice()).relatedId(drpProcurementContract.getContractId()).remark(DrpMaterialPriceTypeEnum.MATERIAL_CONTRACT.value()).build());
      });
   }

   public List<DrpContractPageVO> page(DrpContractPageDTO content) {
      if (CharSequenceUtil.isNotBlank(content.getContractInfo())) {
         content.setContractInfo(LeBeanUtil.fieldLikeHandle(content.getContractInfo()));
      }
      List<DrpContractPageVO> list = this.drpProcurementContractMapper.page(content, DelFlagEnum.DEL_FALSE.key());
      if (CollUtil.isNotEmpty(list)) {
         list.forEach((vo) -> {
            if (vo.getContractStatus() != null && Objects.equals(vo.getContractStatus(), DrpContractStatusEnum.IN_PROGRESS.key())) {
               if (vo.getContractStartTime() != null && vo.getContractStartTime().isAfter(LocalDateTime.now())) {
                  vo.setContractStatus(DrpContractStatusEnum.WAIT_EFFECT.key());
               }

               if (vo.getContractEndTime() != null && vo.getContractEndTime().isBefore(LocalDateTime.now())) {
                  vo.setContractStatus(DrpContractStatusEnum.EXPIRED.key());
               }
            }

         });
      }

      return list;
   }

   public DrpContractPageVO detail(String contractId) {
      if (CharSequenceUtil.isEmpty(contractId)) {
         throw new ServiceException("合同id不能为空");
      } else {
         List<DrpContractPageVO> drpContractPageVOS = this.page((new DrpContractPageDTO()).setContractInfo(contractId));
         if (CollUtil.isNotEmpty(drpContractPageVOS)) {
            DrpContractPageVO drpContractPageVO = drpContractPageVOS.get(0);
            List<DrpContractDetailVO> detailVOList = this.drpProcurementContractMapper.getDetailListByContractId(contractId);
            drpContractPageVO.setDetailList(detailVOList);
            return drpContractPageVO;
         } else {
            return null;
         }
      }
   }

   public void remove(String contractId) {
      if (CharSequenceUtil.isEmpty(contractId)) {
         throw new ServiceException("合同id不能为空");
      } else {
         this.drpProcurementContractMapper.update(null, (Wrappers.lambdaUpdate(DrpProcurementContract.class).set(DrpProcurementContract::getDelFlag, DelFlagEnum.DEL_TRUE.key())).eq(DrpProcurementContract::getContractId, contractId));
      }
   }

   public void close(String contractId) {
      if (CharSequenceUtil.isEmpty(contractId)) {
         throw new ServiceException("合同id不能为空");
      } else {
         this.drpProcurementContractMapper.update(null, (Wrappers.lambdaUpdate(DrpProcurementContract.class).set(DrpProcurementContract::getContractStatus, DrpContractStatusEnum.CLOSED.key())).eq(DrpProcurementContract::getContractId, contractId));
      }
   }
}
