
package com.tmerclub.cloud.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.auth.bo.UidInfoBO;
import com.tmerclub.cloud.api.auth.constant.SysTypeEnum;
import com.tmerclub.cloud.api.multishop.feign.ShopSubstituteSalesFeignClient;
import com.tmerclub.cloud.api.multishop.feign.ShopUserFeignClient;
import com.tmerclub.cloud.api.multishop.vo.ShopUserVO;
import com.tmerclub.cloud.api.product.dto.StockBillLogItemDTO;
import com.tmerclub.cloud.api.product.dto.SupplierSpuUpdateDTO;
import com.tmerclub.cloud.api.product.util.ProductLangUtil;
import com.tmerclub.cloud.api.product.vo.SkuStockVO;
import com.tmerclub.cloud.common.order.vo.WarehouseVO;
import com.tmerclub.cloud.api.supplier.feign.SupplierUserFeignClient;
import com.tmerclub.cloud.api.supplier.vo.SupplierApiUserVO;
import com.tmerclub.cloud.common.cache.constant.CacheNames;
import com.tmerclub.cloud.common.cache.constant.LuaOperateEnum;
import com.tmerclub.cloud.common.cache.constant.ProductCacheNames;
import com.tmerclub.cloud.common.cache.util.RedisUtil;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.StatusEnum;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.i18n.LanguageEnum;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.product.constant.*;
import com.tmerclub.cloud.common.product.dto.*;
import com.tmerclub.cloud.common.product.vo.*;
import com.tmerclub.cloud.common.product.vo.app.SkuAppVO;
import com.tmerclub.cloud.common.product.vo.search.SpuAdminVO;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.common.util.AnalysisUtil;
import com.tmerclub.cloud.common.util.Arith;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.product.constant.DistributedIdKey;
import com.tmerclub.cloud.product.manager.StockManager;
import com.tmerclub.cloud.product.mapper.SkuMapper;
import com.tmerclub.cloud.product.mapper.SpuPriceLogMapper;
import com.tmerclub.cloud.product.mapper.StockPointSkuMapper;
import com.tmerclub.cloud.product.model.Sku;
import com.tmerclub.cloud.product.model.SkuLang;
import com.tmerclub.cloud.product.model.SpuPriceLog;
import com.tmerclub.cloud.product.model.SpuSupplierChangeLog;
import com.tmerclub.cloud.product.service.*;
import com.tmerclub.cloud.product.service.*;
import com.tmerclub.cloud.product.util.StockUtil;
import com.tmerclub.cloud.product.vo.SkuExcelVO;
import com.tmerclub.cloud.product.vo.SpuExcelVO;
import com.tmerclub.cloud.product.vo.SupplierSpuExcelVO;
import org.apache.commons.compress.utils.Lists;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * sku信息
 *
 * @author tmerclub
 * @date 2020-10-28 15:27:24
 */
@Service
public class SkuServiceImpl implements SkuService {

    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private SpuSkuAttrValueService spuSkuAttrValueService;
    @Autowired
    private SkuStockService skuStockService;
    @Autowired
    private SkuLangService skuLangService;
    @Autowired
    private SkuComboService skuComboService;
    @Autowired
    private StockManager stockManager;
    @Autowired
    private SegmentManager segmentManager;
    @Autowired
    private SpuPriceLogMapper spuPriceLogMapper;
    @Autowired
    private RocketMQTemplate stockBillLogTemplate;
    @Autowired
    @Lazy
    private SpuSupplierChangeLogService spuSupplierChangeLogService;
    @DubboReference
    private ShopSubstituteSalesFeignClient shopSubstituteSalesFeignClient;
    @DubboReference
    private ShopUserFeignClient shopUserFeignClient;
    @Autowired
    private StockPointSkuService stockPointSkuService;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private StockPointSkuMapper stockPointSkuMapper;
    @DubboReference
    private SupplierUserFeignClient supplierUserFeignClient;

    private final Logger logger = LoggerFactory.getLogger(SkuServiceImpl.class);


    @Override
    public List<SkuVO> listSku(SkuDTO skuDTO) {
        return skuMapper.listSku(skuDTO);
    }

    @Override
    public List<SkuStockVO> save(Long spuId, Integer spuStatus, List<SkuDTO> skuList, Integer sysType, Long userId, Long shopId,Integer spuMold) {
        batchSaveSku(spuId, skuList);
        List<SkuVO> skuDbList = skuMapper.getBySpuId(spuId);
        List<SkuLangDTO> skuLangList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SkuComboDTO> skuComboList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SkuStockVO> skuStocks = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SpuSkuAttrValueDTO> spuSkuAttrValues = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<StockPointSkuDTO> stockPointS = new ArrayList<>(Constant.INITIAL_CAPACITY);
        WarehouseVO warehouse = warehouseService.getDefaultWarehouseByShopId(shopId, sysType);
        if(Objects.isNull(warehouse)) {
            throw new LuckException("找不到该店铺的默认仓库");
        }
        for (SkuDTO skuDTO : skuList) {
            // 添加库存
            addStockPoint(spuMold, stockPointS, spuId, spuStatus, skuStocks, skuDTO, warehouse.getWarehouseId());
            if(Objects.equals(spuMold,SpuMold.COMBO.value())){
                addCombo(skuComboList, skuDTO);
            }
            if (CollUtil.isEmpty(skuDTO.getSpuSkuAttrValues())) {
                continue;
            }
            addAttr(spuId, spuSkuAttrValues, skuDTO);
            addLang(skuLangList, skuDTO);
        }
        skuLangService.batchSave(BeanUtil.mapAsList(skuLangList, SkuLang.class));
        spuSkuAttrValueService.save(spuSkuAttrValues, sysType);
        stockPointSkuService.batchSave(stockPointS);
        saveSupplierLog(skuList.size() > skuDbList.size(), spuId, SupplierSpuChangeType.ADD_SKU.value());
        for (SkuDTO skuDTO : skuList) {
            skuDTO.setChangeStock(skuDTO.getStock());
        }
//            List<StockBillLogItemVO> stockBillLogItemVOList = loadStockBillLogItems(spuId, skuList);
//            StockBillLogVO stockBillLogVO = loadStockBillLog(StockType.WAREHOUSING.value(), StockBillType.INITIALIZE.value(), stockBillLogItemVOList, userId, shopId);
//            //发送事件进行添加商品库存初始化记录
//            SendStatus sendStockStatus = stockBillLogTemplate.syncSend(RocketMqConstant.OUT_STOCK_LOG_TOPIC, new GenericMessage<>(stockBillLogVO)).getSendStatus();
        // 平台发布的积分商品，没有出入库详情
        if (shopId != Constant.PLATFORM_SHOP_ID) {
            List<StockBillLogItemDTO> stockBillLogItemDTOList = new ArrayList<>();
            stockBillLogItemDTOList.addAll(addBillLogList(StockBillType.INITIALIZE.value(), StockType.WAREHOUSING.value(), BeanUtil.mapAsList(stockPointS, StockPointSkuVO.class), BeanUtil.mapAsList(skuList, SkuVO.class), shopId, null));
            // 入库初始化库存
            SendStatus sendStockStatus = stockBillLogTemplate.syncSend(RocketMqConstant.STOCK_BILL_LOG_TOPIC, new GenericMessage<>(stockBillLogItemDTOList)).getSendStatus();
            if (!Objects.equals(sendStockStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }
        // 保存修改一下组合商品关联
        if(CollectionUtil.isNotEmpty(skuComboList)){
            skuComboService.saveBatch(skuComboList);
        }
        return skuStocks;
    }

    @Override
    public void saveSkuAndStock(Integer spuMold, Long spuId, Integer spuStatus, List<SkuDTO> skuList, Integer sysType, Long userId, Long shopId) {
        List<SkuStockVO> skuStocks = this.save(spuId, spuStatus, skuList, sysType, userId, shopId,spuMold);
        // 数据存储在redis中，所以最后再执行库存插入
        stockManager.skuStock(skuStocks, LuaOperateEnum.SKU_INSERT);
    }

    private void saveSupplierLog(boolean skuList, Long spuId, Integer changeType) {
        //供应商新增sku时，生成对应的变更记录
        if (skuList) {
            SpuSupplierChangeLog spuSupplierChangeLog = new SpuSupplierChangeLog();
            spuSupplierChangeLog.setSpuId(spuId);
            spuSupplierChangeLog.setChangeType(changeType);
            spuSupplierChangeLogService.save(spuSupplierChangeLog);
        }
    }

    private static void addLang(List<SkuLangDTO> skuLangList, SkuDTO skuDTO) {
        for (SkuLangDTO skuLangDTO : skuDTO.getSkuLangList()) {
            skuLangDTO.setSkuId(skuDTO.getSkuId());
            skuLangList.add(skuLangDTO);
        }
    }

    private static void addCombo(List<SkuComboDTO> skuComboList, SkuDTO skuDTO) {
        // 供应商商品代销时为空直接跳过
        if(CollUtil.isEmpty(skuDTO.getSkuComboList())){
            return;
        }
        for (SkuComboDTO skuComboDTO : skuDTO.getSkuComboList()) {
            skuComboDTO.setSkuId(skuDTO.getSkuId());
        }
        skuComboList.addAll(skuDTO.getSkuComboList());
    }

    private static void addAttr(Long spuId, List<SpuSkuAttrValueDTO> spuSkuAttrValues, SkuDTO skuDTO) {
        for (SpuSkuAttrValueDTO spuSkuAttrValue : skuDTO.getSpuSkuAttrValues()) {
            spuSkuAttrValue.setSpuId(spuId);
            spuSkuAttrValue.setSkuId(skuDTO.getSkuId());
            spuSkuAttrValue.setStatus(StatusEnum.ENABLE.value());
            spuSkuAttrValues.add(spuSkuAttrValue);
        }
    }

    private static void addStockPoint(Integer spuMold, List<StockPointSkuDTO> stockPointS, Long spuId, Integer spuStatus, List<SkuStockVO> skuStocks, SkuDTO skuDTO,Long defaultWarehouseId) {
        Integer stockCount = 0;
        Integer status = StatusEnum.DISABLE.value();
        if (Objects.equals(spuStatus, SpuStatus.PUT_SHELF.value()) && Objects.equals(skuDTO.getStatus(), StatusEnum.ENABLE.value())) {
            status = StatusEnum.ENABLE.value();
        }
        // 如果是组合商品,添加一条默认仓库库存为0的数据
        if(Objects.equals(spuMold,SpuMold.COMBO.value())){
            SkuStockVO skuStock = new SkuStockVO(skuDTO.getSkuId(), skuDTO.getStock(), defaultWarehouseId, StockPointType.WAREHOUSE.getValue());
            skuStock.setSpuId(spuId);
            skuStock.setLockStock(0);
            skuStock.setStatus(status);
            skuStocks.add(skuStock);
        }else {
            for (StockPointSkuDTO stockPointSkuDTO : skuDTO.getStockPointList()) {
                stockPointSkuDTO.setSkuId(skuDTO.getSkuId());
                stockPointSkuDTO.setStatus(skuDTO.getStatus());
                stockPointSkuDTO.setSpuId(spuId);
                stockPointS.add(stockPointSkuDTO);
                SkuStockVO skuStock = new SkuStockVO(stockPointSkuDTO.getSkuId(), stockPointSkuDTO.getStock(), stockPointSkuDTO.getStockPointId(), stockPointSkuDTO.getStockPointType());
                stockCount += stockPointSkuDTO.getStock();
                skuStock.setSpuId(spuId);
                skuStock.setLockStock(0);
                skuStock.setStatus(status);
                skuStocks.add(skuStock);
            }
        }
    }

    private void batchSaveSku(Long spuId, List<SkuDTO> skuList) {
        skuList.forEach(sku -> {
            sku.setSpuId(spuId);
            if (Objects.isNull(sku.getStatus())) {
                sku.setStatus(StatusEnum.ENABLE.value());
            }
            if (StrUtil.isBlank(sku.getImgUrl())) {
                sku.setImgUrl(null);
            }
            if (Objects.isNull(sku.getScoreFee())) {
                sku.setScoreFee(Constant.ZERO_LONG);
            }
            if (Objects.isNull(sku.getStockWarning())) {
                sku.setStockWarning(0L);
            }
        });
        // 处理数据，保存库存、属性
        skuMapper.saveBatch(skuList);
    }


    @Override
    public void update(SpuDTO spu, List<SkuDTO> skuList) {
        Integer sysType = AuthUserContext.get().getSysType();
        boolean priceUpdate = false;
        boolean skuUpdate = false;
        // 从获取旧的sku的数据
        List<SkuVO> skuListDb = listSkuWithAttrBySpuId(spu.getSpuId());
        Map<Long, SkuVO> skuMap = skuListDb.stream().collect(Collectors.toMap(SkuVO::getSkuId, x -> x));
        // skuId
        List<Long> skuIdsDb = new ArrayList<>(skuMap.keySet());
        List<Long> skuIds = new ArrayList<>(skuList.size());
        List<SkuDTO> updateSkus = new ArrayList<>(skuList.size());
        List<SkuDTO> insertSkus = new ArrayList<>(skuList.size());
        List<SkuComboDTO> skuComboList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        // 原有sku增加库存的sku列表(不包含新增的sku)
        List<SkuDTO> addStockSkuList = new ArrayList<>(skuList.size());
        // 原有sku减少库存的sku列表(不包含新增的sku)
        List<SkuDTO> reduceStockSkuList = new ArrayList<>(skuList.size());
        String spuName = spu.getSpuLangList().get(0).getSpuName();
        for (SkuDTO sku : skuList) {
            sku.setSpuId(spu.getSpuId());
            sku.setSpuName(spuName);
            sku.setSpuMainImgUrl(spu.getMainImgUrl());
            SkuDTO addSkuDTO = new SkuDTO();
            SkuDTO reduceSkuDTO = new SkuDTO();
            if (skuIdsDb.contains(sku.getSkuId())) {
                List<StockPointSkuDTO> addStockPointList = new ArrayList<>();
                List<StockPointSkuDTO> reduceStockPointList = new ArrayList<>();
                for (StockPointSkuDTO pointSkuDTO : sku.getStockPointList()) {
                    if ((Objects.isNull(pointSkuDTO.getChangeStock()) && Objects.isNull(pointSkuDTO.getStockPointSkuId()))
                            || (Objects.nonNull(pointSkuDTO.getChangeStock()) && pointSkuDTO.getChangeStock() > 0)) {
                        // 库存增加
                        addStockPointList.add(pointSkuDTO);
                    }
                    if (Objects.nonNull(pointSkuDTO.getChangeStock()) && pointSkuDTO.getChangeStock() < 0) {
                        // 库存减少
                        reduceStockPointList.add(pointSkuDTO);
                    }
                }
                if (!addStockPointList.isEmpty()) {
                    addSkuDTO = BeanUtil.map(sku, SkuDTO.class);
                    addSkuDTO.setStockPointList(addStockPointList);
                    addStockSkuList.add(addSkuDTO);
                }
                if (!reduceStockPointList.isEmpty()) {
                    reduceSkuDTO = BeanUtil.map(sku, SkuDTO.class);
                    reduceSkuDTO.setStockPointList(reduceStockPointList);
                    reduceStockSkuList.add(reduceSkuDTO);
                }
                updateSkus.add(sku);
                skuIds.add(sku.getSkuId());
                if(Objects.equals(spu.getSpuMold(),SpuMold.COMBO.value())){
                    addCombo(skuComboList, sku);
                }
            } else if (Objects.isNull(sku.getSkuId())) {
                insertSkus.add(sku);
            }

        }
        List<SkuStockVO> skuStockList = new ArrayList<>(skuList.size());
        // 新增的sku--保存
        if (CollUtil.isNotEmpty(insertSkus)) {
            skuStockList.addAll(this.save(spu.getSpuId(), spu.getStatus(), insertSkus, AuthUserContext.get().getSysType(),
                    AuthUserContext.get().getUserId(), AuthUserContext.get().getTenantId(),spu.getSpuMold()));
            skuUpdate = true;
        }
        // 已有的sku--更新
        if (CollUtil.isNotEmpty(updateSkus)) {
            priceUpdate = getPriceUpdateAndupdateSku(spu, sysType, priceUpdate, updateSkus, skuStockList);
        }
        // 不存在的sku--删除
        skuIdsDb.removeAll(skuIds);
        if (CollUtil.isNotEmpty(skuIdsDb)) {
            deleteSkuBatch(skuIdsDb);
            skuUpdate = true;
        }
        // 更新供应商商品变更状态
        if (Objects.equals(sysType, SysTypeEnum.SUPPLIER.value())) {
            SupplierSpuUpdateDTO spuUpdateDTO = RedisUtil.get(ProductCacheNames.SUPPLIER_SPU_UPDATE_STATUS + spu.getSpuId());
            spuUpdateDTO.setPriceUpdate(priceUpdate);
            spuUpdateDTO.setSkuUpdate(skuUpdate);
            RedisUtil.set(ProductCacheNames.SUPPLIER_SPU_UPDATE_STATUS + spu.getSpuId(), spuUpdateDTO, 0);
            // 检查供应商sku信息变更
            SupplierSpuChangeType changeType = null;
            if (!CollectionUtils.isEmpty(insertSkus)) {
                changeType = SupplierSpuChangeType.ADD_SKU;
            } else if (!CollectionUtil.isEmpty(skuIdsDb)) {
                changeType = SupplierSpuChangeType.SKU_MSG_CHANGE;
            } else {
                for (SkuDTO skuDTO : skuList) {
                    if (this.checkSupplierSkuMsgChange(skuDTO, skuMap.get(skuDTO.getSkuId()))) {
                        changeType = SupplierSpuChangeType.SKU_MSG_CHANGE;
                        break;
                    }
                }
            }
            // 生成供应商信息变更日志
            if (!Objects.isNull(changeType)) {
                SpuSupplierChangeLog changeLog = new SpuSupplierChangeLog();
                changeLog.setSpuId(spu.getSpuId());
                changeLog.setChangeType(changeType.value());
                spuSupplierChangeLogService.save(changeLog);
            }
        }
        //生成库存出入库记录
        if (!Objects.equals(spu.getSpuMold(), SpuMold.COMBO.value())) {
            stockBillLogChange(spu.getSpuId(), null, addStockSkuList, reduceStockSkuList);
        }
        if (CollUtil.isEmpty(skuStockList)) {
            return;
        }
        SpuVO.DeliveryModeVO deliveryModeVO = Json.parseObject(spu.getDeliveryMode(), SpuVO.DeliveryModeVO.class);
        // 判断处理库存
        skuStockService.handSkuStock(spu.getSpuId(), skuStockList, LuaOperateEnum.SKU_REPLACE, deliveryModeVO.getHasUserPickUp());
        //  如果是组合商品关联的sku信息集合不为空,处理一下
        if(CollectionUtil.isNotEmpty(skuComboList)){
            handleComboSku(skuComboList);
        }
    }

    @Override
    public void deleteById(Long skuId) {
        skuMapper.deleteById(skuId);
    }

    @Override
    @Cacheable(cacheNames = CacheNames.SKU_WITH_ATTR_LIST_KEY, key = "#spuId", sync = true)
    public List<SkuVO> listSkuWithAttrBySpuId(Long spuId) {
        List<SkuVO> skuList = skuMapper.listSkuWithAttrBySpuId(spuId);
        for (SkuVO skuVO : skuList) {
            if (StrUtil.isNotBlank(skuVO.getImgUrl())) {
                skuVO.setMainImgUrl(skuVO.getImgUrl());
            }
        }
        List<Long> skuIds = skuList.stream().map(SkuVO::getSkuId).toList();
        // 添加sku区域列表
        List<StockPointSkuVO> stockPointSkuVOList = stockPointSkuMapper.listBySkuIds(skuIds);
        Map<Long, List<StockPointSkuVO>> stockPointSkuMap = stockPointSkuVOList.stream().collect(Collectors.groupingBy(StockPointSkuVO::getSkuId));
        for (SkuVO skuVO : skuList) {
            skuVO.setStockPointList(stockPointSkuMap.get(skuVO.getSkuId()));
        }
        return skuList;
    }

    @Override
    public void deleteBySpuId(SpuDTO spuDTO) {
        //生成编辑出库记录s
        List<SkuVO> skuVOList = skuMapper.getBySpuId(spuDTO.getSpuId());
        List<Long> skuIds = skuVOList.stream().map(SkuVO::getSkuId).collect(Collectors.toList());
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(skuIds);
        // 删除的sku库存
        // 获取sku库存
        List<SkuStockVO> skuStockVOList = stockManager.convertSkuStock(stockPointList);
//        if(CollectionUtil.isEmpty(stockPointList)){
//            skuMapper.updateBySpuId(spuDTO.getSpuId());
//            return;
//        }
        for (StockPointSkuVO stockPointSkuVO : stockPointList) {
            for (SkuStockVO skuStockVO : skuStockVOList) {
                if (stockPointSkuVO.getStockPointId().equals(skuStockVO.getStockPointId())
                        && stockPointSkuVO.getSkuId().equals(skuStockVO.getSkuId())) {
                    stockPointSkuVO.setStock(skuStockVO.getStock());
                }
            }
        }
        Map<Long, List<StockPointSkuVO>> stockPointMap = stockPointList.stream().collect(Collectors.groupingBy(StockPointSkuVO::getSkuId));
        Map<Long, Integer> skuStockMap = skuStockVOList.stream().filter(skuStockVO -> skuStockVO.getStockPointId().equals(StockManager.WAREHOUSE_ID)).collect(Collectors.toMap(SkuStockVO::getSkuId, SkuStockVO::getStock));
        List<SkuDTO> reduceStockSkuList = skuVOList.stream().map(skuVO -> {
            SkuDTO skuDTO = new SkuDTO();
            skuDTO.setSkuId(skuVO.getSkuId());
            skuDTO.setSpuName(spuDTO.getName());
            skuDTO.setSpuMainImgUrl(spuDTO.getMainImgUrl());
            skuDTO.setPriceFee(skuVO.getPriceFee());
            skuDTO.setChangeStock(skuStockMap.get(skuVO.getSkuId()));
            skuDTO.setMarketPriceFee(skuVO.getMarketPriceFee());
            skuDTO.setSpuId(skuVO.getSpuId());
            skuDTO.setPartyCode(skuVO.getPartyCode());
            skuDTO.setStockPointList(BeanUtil.mapAsList(stockPointMap.get(skuVO.getSkuId()), StockPointSkuDTO.class));
            return skuDTO;
        }).collect(Collectors.toList());

        // 记录库存编辑减少记录
        if (!Objects.equals(spuDTO.getSpuMold(), SpuMold.COMBO.value())) {
            handleReduceStockSkuList(reduceStockSkuList, spuDTO.getSpuId(), StockType.OUT_OF_STOCK, StockBillType.EDIT_OUTBOUND);
        }
        skuMapper.updateBySpuId(spuDTO.getSpuId());
        // 删除该商品所有的sku库存
        stockManager.skuStock(skuStockVOList, LuaOperateEnum.SKU_SUB);
        List<Long> pointIdList = stockPointList.stream().map(StockPointSkuVO::getStockPointSkuId).collect(Collectors.toList());
        stockPointSkuService.batchDeleteByStockPointSkuIdList(pointIdList);
    }

    @Override
    @Cacheable(cacheNames = CacheNames.SKU_KEY, key = "#skuId")
    public SkuVO getSkuBySkuId(Long skuId) {
        SkuVO sku = skuMapper.getSkuBySkuId(skuId);
        List<StockPointSkuVO> stockPointSkuList = stockPointSkuService.listPointBySkuIds(Collections.singletonList(sku.getSkuId()));
        stockPointSkuList.sort(Comparator.comparing(StockPointSkuVO::getType));
        sku.setStockPointList(stockPointSkuList);
        return sku;
    }

    @Override
    public void updateAmountOrStock(SpuDTO spuDTO) {
        List<SkuDTO> skuList = spuDTO.getSkuList();
        List<SkuVO> skuDbList = skuMapper.getBySpuId(spuDTO.getSpuId());
        List<Sku> skus = new ArrayList<>(Constant.INITIAL_CAPACITY);
        boolean isUpdateStock = false;
        List<SpuPriceLog> spuPriceLogList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SkuDTO> addStockSkuList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SkuDTO> reduceStockSkuList = new ArrayList<>(Constant.INITIAL_CAPACITY);

        for (SkuDTO skuDTO : skuList) {
            skuDTO.setSpuId(spuDTO.getSpuId());
            skuDTO.setSpuName(spuDTO.getName());
            skuDTO.setSpuMainImgUrl(spuDTO.getMainImgUrl());
            SkuDTO addSkuDTO = new SkuDTO();
            SkuDTO reduceSkuDTO = new SkuDTO();
            if (Objects.nonNull(skuDTO.getChangeStock())) {
                isUpdateStock = true;
                SkuVO skuDb = skuDbList.stream().filter(sku -> Objects.equals(skuDTO.getSkuId(), sku.getSkuId())).findFirst().get();
                skuDTO.setMarketPriceFee(skuDb.getMarketPriceFee());
                skuDTO.setPriceFee(skuDb.getPriceFee());
                skuDTO.setPartyCode(skuDb.getPartyCode());
                skuDTO.setImgUrl(skuDb.getImgUrl());
                skuDTO.setSpuMainImgUrl(spuDTO.getMainImgUrl());
                skuDTO.setStatus(skuDb.getStatus());

//                if (Objects.nonNull(skuDTO.getChangeStock()) && skuDTO.getChangeStock() > 0) {
//                    addStockSkuList.add(skuDTO);
//                } else {
//                    reduceStockSkuList.add(skuDTO);
//                }
                List<StockPointSkuDTO> addStockPointList = new ArrayList<>();
                List<StockPointSkuDTO> reduceStockPointList = new ArrayList<>();
                for (StockPointSkuDTO pointSkuDTO : skuDTO.getStockPointList()) {
                    if ((Objects.isNull(pointSkuDTO.getChangeStock()) && Objects.isNull(pointSkuDTO.getStockPointSkuId()))
                            || Objects.nonNull(pointSkuDTO.getChangeStock()) && pointSkuDTO.getChangeStock() > 0) {
                        // 库存增加
                        addStockPointList.add(pointSkuDTO);
                    }
                    if (Objects.nonNull(pointSkuDTO.getChangeStock()) && pointSkuDTO.getChangeStock() < 0) {
                        // 库存减少
                        reduceStockPointList.add(pointSkuDTO);
                    }
                }
                if (!addStockPointList.isEmpty()) {
                    addSkuDTO = BeanUtil.map(skuDTO, SkuDTO.class);
                    addSkuDTO.setStockPointList(addStockPointList);
                    addStockSkuList.add(addSkuDTO);
                }
                if (!reduceStockPointList.isEmpty()) {
                    reduceSkuDTO = BeanUtil.map(skuDTO, SkuDTO.class);
                    reduceSkuDTO.setStockPointList(reduceStockPointList);
                    reduceStockSkuList.add(reduceSkuDTO);
                }
            } else if (Objects.nonNull(skuDTO.getPriceFee())) {
                //供应商修改商品价格，生成对应的调价记录
                List<SkuVO> skuDb = skuDbList.stream().filter(item -> item.getSkuId().equals(skuDTO.getSkuId())).collect(Collectors.toList());
                if (Objects.equals(AuthUserContext.get().getSysType(), SysTypeEnum.SUPPLIER.value()) && CollUtil.isNotEmpty(skuDb) && (!skuDb.get(0).getPriceFee().equals(skuDTO.getPriceFee()))) {
                    SpuPriceLog spuPriceLog = new SpuPriceLog();
                    spuPriceLog.setSpuId(spuDTO.getSpuId());
                    spuPriceLog.setSkuId(skuDTO.getSkuId());
                    spuPriceLog.setBeforePrice(skuDb.get(0).getPriceFee());
                    spuPriceLog.setAfterPrice(skuDTO.getPriceFee());
                    spuPriceLog.setPrice((long) Arith.sub(spuPriceLog.getAfterPrice(), spuPriceLog.getBeforePrice()));
                    spuPriceLogList.add(spuPriceLog);
                }
                Sku sku = new Sku();
                sku.setSkuId(skuDTO.getSkuId());
                sku.setPriceFee(skuDTO.getPriceFee());
                skus.add(sku);
            }
        }
        if (isUpdateStock) {
            skuStockService.updateBatch(skuList);
            //生成库存出入库记录
            stockBillLogChange(spuDTO.getSpuId(), null, addStockSkuList, reduceStockSkuList);
        }
        if (CollUtil.isNotEmpty(skus)) {
            skuMapper.updateBatch(skus);
        }
        saveSupplierLog(!Objects.equals(spuDTO.getSupplierId(), -1L) && (isUpdateStock || CollUtil.isNotEmpty(skus)), spuDTO.getSpuId(), SupplierSpuChangeType.SKU_MSG_CHANGE.value());
        if (CollUtil.isNotEmpty(spuPriceLogList)) {
            spuPriceLogMapper.insertBatch(spuPriceLogList);
        }

    }

    @Override
    public List<SkuAppVO> getSpuDetailSkuInfo(SpuVO spu) {
        // 从缓存获取sku的数据
        List<SkuVO> skuData;
        // 供应商的sku列表
        if (Objects.nonNull(spu.getSupplierSpuType()) && Objects.equals(spu.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
            skuData = listConsignmentSku(spu, true);
        }
        // 普通商品的sku列表
        else {
            skuData = listSkuAllInfoBySpuId(spu.getSpuId(), spu, true);
        }
        List<SkuAppVO> skuAppList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (SkuVO sku : skuData) {
            SkuAppVO skuAppVO = BeanUtil.map(sku, SkuAppVO.class);
            if (Objects.nonNull(sku.getSupplierStock())) {
                skuAppVO.setStock(sku.getSupplierStock());
            }
            skuAppVO.setProperties(spliceProperties(sku.getSpuSkuAttrValues()));
            skuAppList.add(skuAppVO);
        }
        return skuAppList;
    }

    @Override
    public List<SkuVO> listBySpuIds(List<Long> spuIds) {
        if (CollUtil.isEmpty(spuIds)) {
            return Collections.emptyList();
        }
        // 批量获取sku的数据
        List<SkuVO> skuList = skuMapper.listBySpuIds(spuIds);
        // sku国际化处理
        ProductLangUtil.skuList(skuList);
        // 从缓存获取sku的数据
        setSkuStock(skuList);
        return skuList;
    }

    private static List<SkuVO> getSkuVOList(Long spuId) {
        SkuServiceImpl skuService = (SkuServiceImpl) AopContext.currentProxy();

        // 从缓存获取sku的数据
        List<SkuVO> skus = skuService.listSkuWithAttrBySpuId(spuId);
        // 启用的sku，app查询到的商品是启用sku的商品
        skus = skus.stream().filter(skuVO -> Objects.equals(skuVO.getStatus(), 1)).collect(Collectors.toList());
        return skus;
    }

    @Override
    public List<SkuVO> listSupplierBySpuIds(List<Long> spuIds, Long shopId) {
        // 批量获取供应商商品的sku和spu的信息
        List<SkuVO> supplierSkuList = this.listBySpuIds(spuIds);
        // 获取指定的店铺代销商品的库存
        List<SkuVO> skuList = skuStockService.listSkuStockBySupplierSpuIds(spuIds, shopId);
        this.setSkuStock(skuList);
        Map<Long, Integer> skuStockMap = skuList.stream().collect(Collectors.toMap(SkuVO::getSupplierSkuId, SkuVO::getStock));
        for (SkuVO skuVO : supplierSkuList) {
            skuVO.setSupplierStock(skuVO.getStock());
            skuVO.setStock(skuStockMap.getOrDefault(skuVO.getSkuId(), 0));
        }
        return supplierSkuList;
    }


    @Override
    public String spliceProperties(List<SpuSkuAttrValueVO> spuSkuAttrValueList) {
        StringBuilder properties = new StringBuilder(Constant.INITIAL_CAPACITY);
        for (SpuSkuAttrValueVO spuSkuAttrValue : spuSkuAttrValueList) {
            if (CollUtil.isEmpty(spuSkuAttrValue.getSpuSkuAttrValueLangList())) {
                continue;
            }
            properties.append(spuSkuAttrValue.getAttrName()).append(Constant.COLON).append(spuSkuAttrValue.getAttrValueName()).append(Constant.SEMICOLON);
        }
        if (StrUtil.isBlank(properties.toString())) {
            return properties.toString();
        }
        return properties.substring(0, properties.length() - 1);
    }


    private void deleteSkuBatch(List<Long> skuIds) {
        List<Sku> skus = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (Long skuId : skuIds) {
            Sku sku = new Sku();
            sku.setSkuId(skuId);
            sku.setStatus(StatusEnum.DELETE.value());
            skus.add(sku);
        }
        skuMapper.updateBatch(skus);
        spuSkuAttrValueService.changeStatusBySkuId(skuIds, StatusEnum.DELETE.value());
        // 删除关联数据和库存
        List<StockPointSkuVO> pointSkuVOS = stockPointSkuService.listBySkuIds(skuIds);
        List<Long> stockPointIds = pointSkuVOS.stream().map(StockPointSkuVO::getStockPointSkuId).collect(Collectors.toList());
        List<SkuStockVO> skuStockVOList = BeanUtil.mapAsList(pointSkuVOS, SkuStockVO.class);
        skuStockVOList.forEach(s-> s.setStock(0));
        stockPointSkuService.deleteByIds(stockPointIds);
        stockManager.skuStock(skuStockVOList, LuaOperateEnum.SKU_REPLACE);
    }


    @Override
    public List<SkuVO> listSkuAllInfoBySpuId(Long spuId, SpuVO spu, boolean enable) {
        SkuServiceImpl skuService = (SkuServiceImpl) AopContext.currentProxy();
        // 从缓存获取sku的数据
        List<SkuVO> skus = skuService.listSkuWithAttrBySpuId(spuId);

        if (enable) {
            // 启用的sku，app查询到的商品是启用sku的商品
            skus = skus.stream().filter(skuVO -> Objects.equals(skuVO.getStatus(), 1)).collect(Collectors.toList());
        }

        setSkuStock(skus);
        ProductLangUtil.skuList(skus);
        // 如果是组合商品获取所有组合的商品信息并组装,然后计算出对应库存
        if(Objects.equals(spu.getSpuMold(), SpuMold.COMBO.value())){
            assembleComboSpuListAndStock(skus,spu);
        }
        return skus;
    }


    @Override
    public List<SpuExcelVO> excelSkuList(List<Long> spuIds) {
        if (CollUtil.isEmpty(spuIds)) {
            return new ArrayList<>(0);
        }
        List<SpuExcelVO> spuExcelList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SkuVO> skuList = skuMapper.excelSkuList(spuIds);
        setSkuStock(skuList);
        for (SkuVO skuVO : skuList) {
            SpuExcelVO spuExcelVO = BeanUtil.map(skuVO, SpuExcelVO.class);
            spuExcelVO.setPriceFee(skuVO.getPriceFee().toString());
            spuExcelVO.setMarketPriceFee(skuVO.getMarketPriceFee().toString());
            spuExcelVO.setImgs(skuVO.getImgUrl());
            for (SkuLangVO skuLangVO : skuVO.getSkuLangList()) {
                if (Objects.equals(skuLangVO.getLang(), LanguageEnum.LANGUAGE_ZH_CN.getLang())) {
                    ProductLangUtil.spuSkuAttrValueList(skuVO.getSpuSkuAttrValues(), skuLangVO.getLang());
                    spuExcelVO.setPropertiesZh(spliceProperties(skuVO.getSpuSkuAttrValues()));
                    spuExcelVO.setSkuNameZh(skuLangVO.getSkuName());
                } else if (Objects.equals(skuLangVO.getLang(), LanguageEnum.LANGUAGE_EN.getLang())) {
                    ProductLangUtil.spuSkuAttrValueList(skuVO.getSpuSkuAttrValues(), skuLangVO.getLang());
                }
            }
            spuExcelList.add(spuExcelVO);
        }
        return spuExcelList;
    }

    @Override
    public List<SkuVO> listSkuPriceByIds(List<Long> skuIds) {
        if (CollUtil.isEmpty(skuIds)) {
            return new ArrayList<>(0);
        }
        return skuMapper.listSkuPriceByIds(skuIds);
    }

    @Override
    public List<SkuAddrVO> listSpuDetailByIds(List<Long> skuIds) {
        return skuMapper.listSpuDetailByIds(skuIds);
    }

    @Override
    public Long getMinPriceFeeByIds(List<Long> skuIds) {
        return skuMapper.getMinPriceFeeByIds(skuIds);
    }

    @Override
    public List<SupplierSpuExcelVO> excelSupplierSkuList(List<Long> spuIds) {
        if (CollUtil.isEmpty(spuIds)) {
            return new ArrayList<>(0);
        }
        List<SupplierSpuExcelVO> spuExcelList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SkuVO> skuList = skuMapper.excelSkuList(spuIds);
        setSkuStock(skuList);
        List<Long> supplierSkuIds = skuList.stream().map(SkuVO::getSupplierSkuId).collect(Collectors.toList());
        //根据供应商品sku获取供货价
        List<SkuVO> skuVoList = skuMapper.listSkuPriceByIds(supplierSkuIds);
        Map<Long, Long> collect = skuVoList.stream().collect(Collectors.toMap(SkuVO::getSkuId, SkuVO::getPriceFee));
        for (SkuVO skuVO : skuList) {
            SupplierSpuExcelVO spuExcelVO = BeanUtil.map(skuVO, SupplierSpuExcelVO.class);
            spuExcelVO.setPriceFee(skuVO.getPriceFee().toString());
            spuExcelVO.setMarketPriceFee(skuVO.getMarketPriceFee().toString());
            //设置供货价
            String supplierPrice = collect.get(skuVO.getSupplierSkuId()).toString();
            spuExcelVO.setSupplyPrice(supplierPrice);
            for (SkuLangVO skuLangVO : skuVO.getSkuLangList()) {
                if (Objects.equals(skuLangVO.getLang(), LanguageEnum.LANGUAGE_ZH_CN.getLang())) {
                    ProductLangUtil.spuSkuAttrValueList(skuVO.getSpuSkuAttrValues(), skuLangVO.getLang());
                    spuExcelVO.setPropertiesZh(spliceProperties(skuVO.getSpuSkuAttrValues()));
                    spuExcelVO.setSkuNameZh(skuLangVO.getSkuName());
                }
            }
            spuExcelList.add(spuExcelVO);
        }
        return spuExcelList;
    }

    @Override
    public List<SkuVO> listByPartyCodeList(List<String> partyCodeList) {
        return skuMapper.listByPartyCodeList(partyCodeList);
    }

    @Override
    public List<SkuVO> listConsignmentSku(SpuVO spu, boolean enable) {
        SkuServiceImpl skuService = (SkuServiceImpl) AopContext.currentProxy();
        //获取供应商品sku
        List<SkuVO> supplierSkuList = skuService.listSkuWithAttrBySpuId(spu.getSupplierSpuId());
        Map<Long, SkuVO> supplierSkuMap = supplierSkuList.stream().collect(Collectors.toMap(SkuVO::getSkuId, s -> s));
        //代销商品SKU
        List<SkuVO> skuVoList = skuService.listSkuWithAttrBySpuId(spu.getSpuId());
        //获取商家和供应商的sku库存
        List<Long> skuIds = skuVoList.stream().map(SkuVO::getSkuId).collect(Collectors.toList());
        //添加供应商skuId
        skuIds.addAll(supplierSkuMap.keySet());
        //获取商家的库存点关联数据
        List<StockPointSkuVO> stockPointS = stockPointSkuMapper.listBySkuIds(skuIds);
        Map<String, SkuStockVO> skuStockMap = skuStockService.mapSkuTotalStockAndPointStock(stockPointS);
        List<SkuVO> deletedsupplierSkuVoList = new ArrayList<>(Constant.INITIAL_CAPACITY);
//        if(Objects.equals(spu.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value()) && Objects.equals(spu.getSpuMold(), SpuMold.COMBO.value())){
        for (SkuVO skuVO : skuVoList) {
            SkuStockVO skuTotalStock = skuStockMap.get(skuVO.getSkuId().toString());
            if(Objects.nonNull(skuTotalStock)) {
                skuVO.setStock(skuTotalStock.getStock());
                skuVO.setSaleNum(skuTotalStock.getSale());
            }
            if(CollUtil.isNotEmpty(skuVO.getStockPointList())) {
                for (StockPointSkuVO stockPointSkuVO : skuVO.getStockPointList()) {
                    SkuStockVO skuPointStock = skuStockMap.get(StockUtil.skuPointKey(skuVO.getSkuId(), stockPointSkuVO.getStockPointId()));
                    stockPointSkuVO.setStock(skuPointStock.getStock());
                }
            }

            //供应商商品信息
            SkuVO supplierSkuVO = supplierSkuMap.get(skuVO.getSupplierSkuId());
            if (Objects.isNull(supplierSkuVO)) {
                deletedsupplierSkuVoList.add(skuVO);
                continue;
            }
            if (Objects.equals(spu.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
                logger.info("供应商发货代销商品，代销商品sku状态为供应商商品sku状态");
                skuVO.setStatus(supplierSkuVO.getStatus());
            }
            skuVO.setWeight(supplierSkuVO.getWeight());
            skuVO.setVolume(supplierSkuVO.getVolume());
            skuVO.setSupplyPriceFee(supplierSkuVO.getPriceFee());
            skuVO.setSupplierSkuCode(supplierSkuVO.getPartyCode());
            skuVO.setSupplierSkuStatus(supplierSkuVO.getStatus());
            if (supplierSkuVO.getStatus() >= 0) {
                skuVO.setIsSell(supplierSkuVO.getStatus());
            }
            // 供应商只有总库存数据
            SkuStockVO supplierSkuStockVO = skuStockMap.get(skuVO.getSupplierSkuId().toString());
            skuVO.setSupplierStock(Objects.isNull(supplierSkuStockVO) ? 0 : supplierSkuStockVO.getStock());
        }
        //移除供应商已删除的sku
        skuVoList.removeAll(deletedsupplierSkuVoList);
        if (enable) {
            // 启用的sku，app查询到的商品是启用sku的商品
            skuVoList = skuVoList.stream().filter(skuVO -> Objects.equals(skuVO.getSupplierSkuStatus(), 1)).collect(Collectors.toList());
        }
        ProductLangUtil.skuList(skuVoList);
        // 如果是组合商品获取所有组合的商品信息并组装,然后计算出对应库存
        if(Objects.equals(spu.getSpuMold(), SpuMold.COMBO.value())){
            assembleComboSpuListAndStock(skuVoList,spu);
        }
        return skuVoList;
    }

    @Override
    public StockBillLogItemDTO getSkuByPartyCodeAndShopId(String partyCode, Long shopId, Integer sysType) {
        return skuMapper.getSkuByPartyCodeAndShopId(partyCode, shopId, sysType);
    }

    @Override
    public List<String> listSkuPartyCodesByShopId(Long shopId, Integer sysType, Long spuId) {

        return skuMapper.listSkuPartyCodesByShopId(shopId, sysType, spuId);
    }


    @Override
    public List<SkuExcelVO> exportSkuList(ProductSearchDTO product) {
        List<SkuVO> skuList = skuMapper.listExportSku(product);
        // 插入sku库存
        setSkuStock(skuList);
        List<SkuExcelVO> skuExcelList;
        skuExcelList = skuList.stream().map(skuVO -> {
            SkuExcelVO skuExcelVO = new SkuExcelVO();
            skuExcelVO.setSkuId(skuVO.getSkuId());
            skuExcelVO.setSkuName(skuVO.getSkuName());
            skuExcelVO.setSpuName(skuVO.getSpuName());
            skuExcelVO.setPartyCode(skuVO.getPartyCode());
            skuExcelVO.setStock(skuVO.getStock());
            skuExcelVO.setPriceFee(AnalysisUtil.conversionPrices(skuVO.getPriceFee().toString()));
            return skuExcelVO;
        }).collect(Collectors.toList());
        return skuExcelList;
    }

    @Override
    public Integer getStockWarningNum(ProductSearchDTO product) {
        // TODO stock
        return skuMapper.getStockWarningNum(product);
    }

    @Override
    public void commissionSave(SpuVO spuVO, List<SkuDTO> skuList, Integer sysType) {
        Long spuId = spuVO.getSpuId();
        Integer spuStatus = spuVO.getStatus();
        batchSaveSku(spuId, skuList);
        List<SkuVO> skuDbList = skuMapper.getBySpuId(spuId);
        List<SkuStockVO> skuStocks = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SkuLangDTO> skuLangList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<StockPointSkuDTO> stockPointS = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SpuSkuAttrValueDTO> spuSkuAttrValues = new ArrayList<>(Constant.INITIAL_CAPACITY);
        WarehouseVO warehouse = warehouseService.getDefaultWarehouseByShopId(spuVO.getShopId(), sysType);
        if(Objects.isNull(warehouse)) {
            throw new LuckException("找不到该店铺的默认仓库");
        }
        for (SkuDTO skuDTO : skuList) {
            addStockPoint(spuVO.getSpuMold(), stockPointS, spuId, spuStatus, skuStocks, skuDTO, warehouse.getWarehouseId());
            if (CollUtil.isEmpty(skuDTO.getSpuSkuAttrValues())) {
                continue;
            }
            addLang(skuLangList, skuDTO);
            addAttr(spuId, spuSkuAttrValues, skuDTO);
        }
        skuLangService.batchSave(BeanUtil.mapAsList(skuLangList, SkuLang.class));
        spuSkuAttrValueService.commissionSave(spuSkuAttrValues, sysType);
        stockPointSkuService.batchSave(stockPointS);
        //供应商新增sku时，生成对应的变更记录
        saveSupplierLog(skuList.size() > skuDbList.size(), spuId, SupplierSpuChangeType.ADD_SKU.value());
        // 数据存储在redis中，所以最后再执行库存插入
        skuStockService.batchSave(skuStocks, spuStatus);
    }

    @Override
    public List<SkuVO> getByIds(List<Long> skuIds) {
        return skuMapper.listSkuBySkuIds(skuIds);
    }

    @Override
    public List<SpuAdminVO> setSpuSku(List<SpuAdminVO> spuAdminVOList) {
        List<Long> spuIdList = spuAdminVOList.stream().map(SpuAdminVO::getSpuId).collect(Collectors.toList());
        if (spuIdList.size() == 0) {
            return spuAdminVOList;
        }
        List<SkuVO> skuList = skuMapper.listSkuBySpuIds(spuIdList);
        Map<Long, List<SkuVO>> skuVoBySpuId = skuList.stream().collect(Collectors.groupingBy(SkuVO::getSpuId));
        skuList.clear();
        List<Long> spuIdsOfSupplierDelivery = new ArrayList<>(spuAdminVOList.size());
        for (SpuAdminVO spuAdminVO : spuAdminVOList) {
            List<SkuVO> skuVoList = skuVoBySpuId.get(spuAdminVO.getSpuId());
            if (Objects.equals(spuAdminVO.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
                logger.info("供应商自发货商品");
                List<Long> supplierSkuIdList = skuVoList.stream().map(SkuVO::getSupplierSkuId).collect(Collectors.toList());
                List<SkuVO> supplierSkuList = skuMapper.listSkuBySkuIds(supplierSkuIdList);
                Map<Long, Integer> supplierSkuStatusMap = supplierSkuList.stream().collect(Collectors.toMap(SkuVO::getSkuId, SkuVO::getStatus));
                Iterator<SkuVO> iterator = skuVoList.iterator();
                while (iterator.hasNext()) {
                    SkuVO skuVO = iterator.next();
                    if (Objects.equals(supplierSkuStatusMap.get(skuVO.getSupplierSkuId()), StatusEnum.DISABLE.value())) {
                        logger.info("供应商自发货商品，过滤掉不是正常状态的sku，skuId:{}", skuVO.getSkuId());
                        iterator.remove();
                    }
                }
            }
            if (Objects.equals(spuAdminVO.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
                spuIdsOfSupplierDelivery.add(spuAdminVO.getSpuId());
            }
            // 插入sku列表
            spuAdminVO.setSkuList(skuVoList);
            skuList.addAll(skuVoList);
        }
        // sku国际化处理
        ProductLangUtil.skuList(skuList);
        // 获取库存信息
        setSkuAndSupplierSkuStock(skuList, spuIdsOfSupplierDelivery);

        return spuAdminVOList;
    }

    @Override
    public PageVO<SkuVO> pageSku(PageDTO pageDTO, ProductSearchDTO product) {
        PageVO<SkuVO> skuPage = PageUtil.doPage(pageDTO, () -> skuMapper.pageSku(product));
        // 插入库存
        setSkuStock(skuPage.getList());
        return skuPage;
    }

    @Override
    public List<SkuVO> listSkuAndStockBySkuIds(List<Long> skuIds) {
        if (CollectionUtils.isEmpty(skuIds)) {
            return Collections.emptyList();
        }
        // 获取sku信息列表
        List<SkuVO> skuList = skuMapper.listSkuBySkuIds(skuIds);
        // 获取sku总库存信息集合
        Map<Long, SkuStockVO> stockMap = skuStockService.mapSkuTotalStockBySkuIds(skuIds);
        // 设置sku库存
        for (SkuVO skuVO : skuList) {
            SkuStockVO skuStockVO = stockMap.get(skuVO.getSkuId());
            skuVO.setStock(skuStockVO.getStock());
        }
        return skuList;
    }

    @Override
    public void setSkuStock(List<SkuVO> skus) {
        if (CollectionUtil.isEmpty(skus)) {
            return;
        }
        List<Long> skuIds = skus.stream().map(SkuVO::getSkuId).collect(Collectors.toList());
        List<StockPointSkuVO> stockPoints = stockPointSkuMapper.listBySkuIds(skuIds);
        List<Long> comboSkuList = Lists.newArrayList();
        for (SkuVO skuVO : skus) {
            if(Objects.equals(skuVO.getSpuMold(), SpuMold.COMBO.value())) {
                comboSkuList.add(skuVO.getSkuId());
            }
        }
        if(CollUtil.isEmpty(stockPoints)){
            return;
        }
        // 因为库存的缓存是经常变的，而规格信息的缓存是几乎不变的，所以库存的缓存要独立拿出来
        Map<String, SkuStockVO> skuStockMap = skuStockService.mapSkuTotalStockAndPointStock(stockPoints);
        Map<Long, List<StockPointSkuVO>> stockPointMap = stockPoints.stream().collect(Collectors.groupingBy(StockPointSkuVO::getSkuId));
        for (SkuVO skuVO : skus) {
            if (!skuStockMap.containsKey(skuVO.getSkuId().toString())) {
                continue;
            }
            if (!stockPointMap.containsKey(skuVO.getSkuId())) {
                continue;
            }
            List<StockPointSkuVO> stockPointSkuVOList = stockPointMap.get(skuVO.getSkuId());
            for (StockPointSkuVO pointSkuVO : stockPointSkuVOList) {
                SkuStockVO skuStockVO = skuStockMap.get(StockUtil.skuPointKey(skuVO.getSkuId(), pointSkuVO.getStockPointId()));
                pointSkuVO.setStock(skuStockVO.getStock());
            }
            skuVO.setStockPointList(stockPointSkuVOList.stream().filter(stockPointSkuVO -> Objects.nonNull(stockPointSkuVO.getStockPointSkuId()) && stockPointSkuVO.getStockPointId() != 0).collect(Collectors.toList()));

            SkuStockVO skuStockVO = skuStockMap.get(skuVO.getSkuId().toString());
            skuVO.setStock(skuStockVO.getStock());
            skuVO.setSaleNum(skuStockVO.getSale());
        }
        // 如果是组合商品,需要重新计算一下库存
        if (CollUtil.isNotEmpty(comboSkuList)) {
            Map<Long, SkuStockVO> comSkuStockMap = skuStockService.mapSkuTotalStockBySkuIds(comboSkuList);
            for (SkuVO skuVO : skus) {
                if(!comSkuStockMap.containsKey(skuVO.getSkuId())){
                    continue;
                }
                skuVO.setStock(comSkuStockMap.get(skuVO.getSkuId()).getStock());
            }
        }
    }

    @Override
    public void setEsSkuStock(List<SkuVO> skus) {
        List<Long> skuIds = skus.stream().map(SkuVO::getSkuId).collect(Collectors.toList());
        // 获取sku总库存 - 因为库存的缓存是经常变的，而规格信息的缓存是几乎不变的，所以库存的缓存要独立拿出来
        Map<Long, SkuStockVO> skuStockMap = skuStockService.mapSkuTotalStockBySkuIds(skuIds);
        for (SkuVO skuVO : skus) {
            SkuStockVO skuStockVO = skuStockMap.get(skuVO.getSkuId());
            skuVO.setStock(skuStockVO.getStock());
            skuVO.setSaleNum(skuStockVO.getSale());
        }
    }

    @Override
    public void changeSkuStockStatusBySpuId(Long spuId, Integer changeStatus) {
        List<SkuVO> skuList = skuMapper.listSimpleSkuBySpuIds(Collections.singletonList(spuId));
        if (CollUtil.isEmpty(skuList)) {
            return;
        }
        List<SkuStockVO> skuStockList = new ArrayList<>(skuList.size());
        for (SkuVO skuVO : skuList) {
            SkuStockVO skuStock = new SkuStockVO(skuVO.getSkuId());
            if (Objects.equals(changeStatus, SpuStatus.PUT_SHELF.value()) && Objects.equals(skuVO.getStatus(), StatusEnum.ENABLE.value())) {
                skuStock.setStatus(StatusEnum.ENABLE.value());
            } else {
                skuStock.setStatus(StatusEnum.DISABLE.value());
            }
            skuStockList.add(skuStock);
        }
        skuStockService.changeSkuStatus(skuStockList);
    }

    @Override
    public void changeSkuStockStatusBySkuId(Long skuId, Integer spuStatus, Integer skuStatus) {
        SkuStockVO skuStockVO = new SkuStockVO(skuId);
        if (Objects.equals(skuStatus, SpuStatus.PUT_SHELF.value()) && Objects.equals(skuStatus, StatusEnum.ENABLE.value())) {
            skuStockVO.setStatus(StatusEnum.ENABLE.value());
        } else {
            skuStockVO.setStatus(StatusEnum.DISABLE.value());
        }
        skuStockService.changeSkuStatus(Collections.singletonList(skuStockVO));
    }


    @Override
    public List<SkuVO> listSkuAndStockByStockPointId(Long stockPointId, Long inStockPointId) {
        List<StockPointSkuVO> pointSkuList = stockPointSkuService.listByPointId(stockPointId);
        List<Long> skuIds = pointSkuList.stream().map(StockPointSkuVO::getSkuId).collect(Collectors.toList());
        // 获取sku信息列表
        List<SkuVO> skuList = skuMapper.listSkuBySkuIds(skuIds);
        // 获取库存信息集合
        boolean isAllotQuery = !Objects.isNull(inStockPointId);
        if (isAllotQuery) {
            for (Long skuId : skuIds) {
                pointSkuList.add(new StockPointSkuVO(skuId, inStockPointId));
            }
        }
        Map<String, SkuStockVO> skuStockVOMap = skuStockService.mapSkuTotalStockAndPointStock(pointSkuList);
        // 设置sku库存
        List<SkuVO> allotSkuList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (SkuVO skuVO : skuList) {
            SkuStockVO skuStockVO = skuStockVOMap.get(StockUtil.skuPointKey(skuVO.getSkuId(), stockPointId));
            skuVO.setStock(skuStockVO.getStock());
            if (isAllotQuery) {
                if (Objects.equals(skuVO.getStock() ,0)) {
                    continue;
                }
                allotSkuList.add(skuVO);
                // 补充入库点该sku库存
                SkuStockVO skuPointStockVO = skuStockVOMap.get(StockUtil.skuPointKey(skuVO.getSkuId(), inStockPointId));
                skuVO.setInStockPointStock(Objects.isNull(skuPointStockVO) ? 0 : skuPointStockVO.getStock());
            }
        }
        return isAllotQuery ? allotSkuList : skuList;
    }

    private boolean getPriceUpdateAndupdateSku(SpuDTO spu, Integer sysType, boolean priceUpdate, List<SkuDTO> updateSkus, List<SkuStockVO> skuStockList) {
        List<Sku> skus = BeanUtil.mapAsList(updateSkus, Sku.class);
        List<SkuVO> skuDbPriceList = skuMapper.listSkuBySkuIds(updateSkus.stream().map(SkuDTO::getSkuId).collect(Collectors.toList()));
        List<SpuPriceLog> spuPriceLogList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<StockPointSkuDTO> updateStockPointS = new ArrayList<>(Constant.INITIAL_CAPACITY);
        WarehouseVO warehouse = warehouseService.getDefaultWarehouseByShopId(spu.getShopId() == null ? spu.getSupplierId() : spu.getShopId(), sysType);
        if(Objects.isNull(warehouse)) {
            throw new LuckException("找不到该店铺的默认仓库");
        }
        for (SkuVO skuVO : skuDbPriceList) {
            List<SkuDTO> skuGetById = updateSkus.stream().filter(item -> item.getSkuId().equals(skuVO.getSkuId())).collect(Collectors.toList());
            if (Objects.equals(sysType, SysTypeEnum.SUPPLIER.value())
                    && CollUtil.isNotEmpty(skuGetById)) {
                SkuDTO skudto = skuGetById.get(0);
                //供应商修改商品价格时，生成调价记录
                if (!Objects.equals(skudto.getPriceFee(), skuVO.getPriceFee())) {
                    SpuPriceLog spuPriceLog = new SpuPriceLog();
                    spuPriceLog.setSpuId(skuVO.getSpuId());
                    spuPriceLog.setSkuId(skuVO.getSkuId());
                    spuPriceLog.setBeforePrice(skuVO.getPriceFee());
                    spuPriceLog.setAfterPrice(skuGetById.get(0).getPriceFee());
                    spuPriceLog.setPrice((long) Arith.sub(spuPriceLog.getAfterPrice(), spuPriceLog.getBeforePrice()));
                    spuPriceLogList.add(spuPriceLog);
                    // 记录供应商商品售价变化
                    priceUpdate = true;
                }
                if (!Objects.equals(skudto.getMarketPriceFee(), skuVO.getMarketPriceFee())) {
                    priceUpdate = true;
                }
            }
        }
        skuMapper.updateBatch(skus);
        for (SkuDTO sku : updateSkus) {
            addStockPoint(spu.getSpuMold(), updateStockPointS, spu.getSpuId(), spu.getStatus(), skuStockList, sku, warehouse.getWarehouseId());
        }
        if (CollUtil.isNotEmpty(updateStockPointS)) {
            stockPointSkuService.changeStockPoint(updateStockPointS, false);
        }
        if (CollUtil.isNotEmpty(spuPriceLogList)) {
            spuPriceLogMapper.insertBatch(spuPriceLogList);
        }
        return priceUpdate;
    }

    private void stockBillLogChange(Long spuId, List<SkuDTO> insertSkus, List<SkuDTO> addStockSkuList, List<SkuDTO> reduceStockSkuList) {
        // 记录新增的sku库存初始化
        if (CollUtil.isNotEmpty(insertSkus) && AuthUserContext.get().getTenantId() != Constant.PLATFORM_SHOP_ID) {
//            //获取入库单号
//            ServerResponseEntity<Long> inStockResponse = segmentManager.getSegmentId(DistributedIdKey.tmerclub_PRODUCT_STOCK_IN);
//            if (!inStockResponse.isSuccess()) {
//                throw new LuckException(inStockResponse.getMsg());
//            }
//            List<StockBillLogItemVO> stockBillLogItemVOList = loadStockBillLogItems(spuId, insertSkus);
//            StockBillLogVO stockBillLogVO = loadStockBillLog(StockType.WAREHOUSING.value(), StockBillType.INITIALIZE.value(), stockBillLogItemVOList,
//                    AuthUserContext.get().getUserId(), AuthUserContext.get().getTenantId());
//            //发送事件进行添加商品库存初始化记录
//            SendStatus sendStockStatus = stockBillLogTemplate.syncSend(RocketMqConstant.STOCK_BILL_LOG_TOPIC, new GenericMessage<>(stockBillLogVO)).getSendStatus();
            List<StockBillLogItemDTO> stockBillLogItemDTOList =  loadStockBillLogItems(StockType.WAREHOUSING.value(), StockBillType.INITIALIZE.value(), spuId, insertSkus);
            // 发送事件进行添加商品出入库记录
            SendStatus sendStockStatus = stockBillLogTemplate.syncSend(RocketMqConstant.STOCK_BILL_LOG_TOPIC, new GenericMessage<>(stockBillLogItemDTOList)).getSendStatus();
            if (!Objects.equals(sendStockStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }
        // 记录库存编辑增加记录
        handleReduceStockSkuList(addStockSkuList, spuId, StockType.WAREHOUSING, StockBillType.EDIT_STORAGE);
        // 记录库存编辑减少记录
        handleReduceStockSkuList(reduceStockSkuList, spuId, StockType.OUT_OF_STOCK, StockBillType.EDIT_OUTBOUND);
    }

    private void handleReduceStockSkuList(List<SkuDTO> reduceStockSkuList, Long spuId, StockType outOfStock, StockBillType editOutbound) {
        if (CollUtil.isNotEmpty(reduceStockSkuList) && AuthUserContext.get().getTenantId() != Constant.PLATFORM_SHOP_ID) {
//            List<StockBillLogItemVO> stockBillLogItemVOList = loadStockBillLogItems(spuId, reduceStockSkuList);
//            StockBillLogVO stockBillLogVO = loadStockBillLog(outOfStock.value(), editOutbound.value(), stockBillLogItemVOList,
//                    AuthUserContext.get().getUserId(), AuthUserContext.get().getTenantId());
//            //发送事件进行添加商品库存初始化记录
//            SendStatus sendStockStatus = stockBillLogTemplate.syncSend(RocketMqConstant.STOCK_BILL_LOG_TOPIC, new GenericMessage<>(stockBillLogVO)).getSendStatus();

            List<StockBillLogItemDTO> stockBillLogItemDTOList = loadStockBillLogItems(outOfStock.value(), editOutbound.value() ,spuId, reduceStockSkuList);
            // 发送事件进行添加商品出入库记录
            SendStatus sendStockStatus = stockBillLogTemplate.syncSend(RocketMqConstant.STOCK_BILL_LOG_TOPIC, new GenericMessage<>(stockBillLogItemDTOList)).getSendStatus();
            if (!Objects.equals(sendStockStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }
    }

    private StockBillLogVO loadStockBillLog(Integer type, Integer stockBillType, List<StockBillLogItemVO> stockBillLogItems, Long userId, Long shopId) {
        String key = Objects.equals(type, StockType.WAREHOUSING.value()) ? DistributedIdKey.tmerclub_PRODUCT_STOCK_IN : DistributedIdKey.tmerclub_PRODUCT_STOCK_OUT;
        //获取入库单号
        String stockBillNo = segmentManager.getSegmentCode(key);

        ServerResponseEntity<ShopUserVO> userResponse = shopUserFeignClient.getByUserId(userId);
        if (!userResponse.isSuccess() || userResponse.getData() == null) {
            throw new LuckException("无法获取制单人手机号");
        }
        StockBillLogVO stockBillLog = new StockBillLogVO();
        stockBillLog.setType(type);
        stockBillLog.setStockBillNo(stockBillNo);
        stockBillLog.setMakerMobile(userResponse.getData().getPhoneNum());
        stockBillLog.setStockBillType(stockBillType);
        stockBillLog.setShopId(shopId);
        stockBillLog.setEmployeeId(userId);
        stockBillLog.setStatus(StockBillStatus.SUCCESS.value());
        stockBillLog.setBusinessTime(new Date());
        long totalAmount = 0L;
        int totalCount = 0;
        for (StockBillLogItemVO stockBillLogItem : stockBillLogItems) {
            totalAmount = totalAmount + stockBillLogItem.getUnitPrice() * stockBillLogItem.getStockCount();
            totalCount += stockBillLogItem.getStockCount();
        }
        stockBillLog.setTotalAmount(totalAmount);
        stockBillLog.setTotalCount(totalCount);
        stockBillLog.setStockBillLogItems(stockBillLogItems);
        stockBillLog.setStockBillLogItems(stockBillLogItems);
        return stockBillLog;
    }

    private List<StockBillLogItemDTO> loadStockBillLogItems(Integer type, Integer stockBillType, Long spuId, List<SkuDTO> insertSkus) {
        List<StockBillLogItemDTO> stockBillLogItems = new ArrayList<>(Constant.INITIAL_CAPACITY);
        Long userId = AuthUserContext.get().getUserId();
        Integer sysType = AuthUserContext.get().getSysType();
        String userPhone;
        if (sysType.equals(SysTypeEnum.MULTISHOP.value())) {
            ServerResponseEntity<ShopUserVO> userResponse = shopUserFeignClient.getByUserId(userId);
            if (!userResponse.isSuccess() || userResponse.getData() == null) {
                throw new LuckException("无法获取制单人手机号");
            }
            userPhone = userResponse.getData().getPhone();
        } else {
            ServerResponseEntity<SupplierApiUserVO> supplierResponse = supplierUserFeignClient.getByUserId(userId);
            if (!supplierResponse.isSuccess() || supplierResponse.getData() == null) {
                throw new LuckException("无法获取制单人手机号");
            }
            userPhone = supplierResponse.getData().getPhone();
        }
        Long shopId = AuthUserContext.get().getTenantId();
        for (SkuDTO skuDTO : insertSkus) {
            List<StockPointSkuDTO> stockPointList = skuDTO.getStockPointList();
            for (StockPointSkuDTO stockPointSkuDTO : stockPointList) {
                StockBillLogItemDTO stockBillLogItem = new StockBillLogItemDTO();
                stockBillLogItem.setSpuId(spuId);
                stockBillLogItem.setShopId(shopId);
                stockBillLogItem.setSkuId(skuDTO.getSkuId());
                stockBillLogItem.setSpuName(skuDTO.getSpuName());
                stockBillLogItem.setSkuName(skuDTO.getSkuName());
                stockBillLogItem.setMainImgUrl(Objects.nonNull(skuDTO.getImgUrl()) ? skuDTO.getImgUrl() : skuDTO.getSpuMainImgUrl());
                stockBillLogItem.setUnitPrice(skuDTO.getPriceFee());
                stockBillLogItem.setStockCount(Objects.isNull(stockPointSkuDTO.getChangeStock()) ? stockPointSkuDTO.getStock() : Math.abs(stockPointSkuDTO.getChangeStock()));
                stockBillLogItem.setPartyCode(skuDTO.getPartyCode());
                stockBillLogItem.setAfterStock(skuDTO.getChangeStock());
                stockBillLogItem.setUnitPrice(skuDTO.getMarketPriceFee());
                stockBillLogItem.setStockPointId(stockPointSkuDTO.getStockPointId());
                stockBillLogItem.setStockPointType(stockPointSkuDTO.getStockPointType());
                stockBillLogItem.setStocktype(type);
                stockBillLogItem.setStockBillType(stockBillType);
                stockBillLogItem.setMakerMobile(userPhone);
                if (sysType.equals(SysTypeEnum.SUPPLIER.value())) {
                    stockBillLogItem.setSupplierId(shopId);
                    stockBillLogItem.setShopId(-1L);
                }
                stockBillLogItems.add(stockBillLogItem);
            }
        }
        return stockBillLogItems;
    }

    private void handleComboSku(List<SkuComboDTO> skuComboList) {
        List<Long> skuIds = skuComboList.stream().map(SkuComboDTO::getSkuId).toList();
        skuComboService.deleteBySkuIds(skuIds);
        skuComboService.saveBatch(skuComboList);
    }

    /**
     * 设置sku和供应商sku库存
     * 供应商发货的商品，sku库存为供应商商品sku的库存
     * @param skus sku列表
     * @param spuIds 供应商发货的spuId列表
     */
    private void setSkuAndSupplierSkuStock(List<SkuVO> skus, List<Long> spuIds) {
        // 供应商发货的商品，获取供应商sku的库存； 商家发货的商品，获取商品sku的库存
        List<Long> skuIds = skus.stream()
                .map(skuVO -> spuIds.contains(skuVO.getSpuId()) ? skuVO.getSupplierSkuId() : skuVO.getSkuId())
                .collect(Collectors.toList());
        // 因为库存的缓存是经常变的，而规格信息的缓存是几乎不变的，所以库存的缓存要独立拿出来
        Map<String, SkuStockVO> skuStockMap = skuStockService.skuStockMapBySkuIds(skuIds);
        for (SkuVO skuVO : skus) {
            long skuId = spuIds.contains(skuVO.getSpuId()) ? skuVO.getSupplierSkuId() : skuVO.getSkuId();
            if (!skuStockMap.containsKey(skuId)) {
                continue;
            }
            SkuStockVO skuStockVO = skuStockMap.get(skuId);
            skuVO.setStock(skuStockVO.getStock());
            skuVO.setSaleNum(skuStockVO.getSale());
        }
    }

    @Override
    public void assembleComboSpuListAndStock(List<SkuVO> skus,SpuVO spu) {
        Long shopId = spu.getShopId();
        List<Long> skuIds = skus.stream().map(SkuVO::getSkuId).toList();
        if (Objects.nonNull(spu.getSupplierDeliveryType()) && Objects.equals(spu.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
            skuIds = skus.stream().map(SkuVO::getSupplierSkuId).toList();
        }
        boolean isSupplierSpu = Objects.nonNull(spu.getSupplierDeliveryType()) && Objects.equals(spu.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value());
        List<SkuComboVO> totalSkuComboList = skuComboService.getCombSpusBySkuIds(skuIds);
        // 获取所有组合的商品库存
        List<Long> comboSkuIds = totalSkuComboList.stream().map(SkuComboVO::getComboSkuId).toList();
        if(CollectionUtil.isEmpty(comboSkuIds)){
            return;
        }
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(comboSkuIds);
        // 获取sku区域库存
        Map<String, SkuStockVO> stockVOMap = skuStockService.mapSkuTotalStockAndPointStock(stockPointList);
//        // 只需要计算仓库的库存
        // 设置一下组合的商品库存
        Map<Long, List<SkuComboVO>> skuComboMap = totalSkuComboList.stream().collect(Collectors.groupingBy(SkuComboVO::getSkuId));
        Map<Long, List<StockPointSkuVO>> skuPoinStockMap = stockPointList.stream().collect(Collectors.groupingBy(StockPointSkuVO::getStockPointId));
        // 根据主组合商品的skuId组成map
        for (SkuVO sku : skus) {
            sku.setStock(0);
            long skuId = sku.getSkuId();
            if (isSupplierSpu) {
                skuId = sku.getSupplierSkuId();
            }
            // 当前sku关联的组合单品列表
            Map<Long,Integer> pointStockMap = new HashMap<>(skuPoinStockMap.size());
            List<SkuComboVO> skuComboList = skuComboMap.get(skuId);
            // 获取每个区域单品的最小组合库存数量
            for (Map.Entry<Long, List<StockPointSkuVO>> entry : skuPoinStockMap.entrySet()) {
                // 跳过总库存
                if (entry.getKey() == 0) {
                    continue;
                }
                List<StockPointSkuVO> stockPointSkus = entry.getValue();
                // 如果当前仓库的所有sku库存为空,或者小于需要查询的sku的数量,表示这些关联的sku没有共同库存跳过即可
                if(CollUtil.isEmpty(stockPointSkus) || stockPointSkus.size() < skuComboList.size()){
                    continue;
                }
                Map<Long, StockPointSkuVO> comboSkuPoinStockMap = stockPointSkus.stream().collect(Collectors.toMap(StockPointSkuVO::getSkuId, Function.identity()));
                // 计算区域中的单品的最小库存数量
                for (SkuComboVO skuComboVO : skuComboList) {
                    StockPointSkuVO stockPointSkuVO = comboSkuPoinStockMap.get(skuComboVO.getComboSkuId());
                    if(Objects.isNull(stockPointSkuVO)){
                        continue;
                    }
                    // 计算sku中每个单品的库存数量
                    // 获取单品的区域库存信息
                    SkuStockVO skuStockVO = stockVOMap.get(StockUtil.skuPointKey(skuComboVO.getComboSkuId(), stockPointSkuVO.getStockPointId()));
                    // 组合sku中单品实际库存数量 = 单品库存数量 / 单品组合数量
                    // 除以组合数量向下取整得出 当前的组合商品-当前仓库 可用库存
                    int pointStock = Math.floorDiv(skuStockVO.getStock(), skuComboVO.getComboCount());
                    // 如果是0就是总库存,直接跳过
                    if (Objects.equals(stockPointSkuVO.getStockPointId(), StockManager.WAREHOUSE_ID)) {
                        continue;
                    }
                    // 组合商品的库存取最小值,比如都是默认仓库的情况下,取最小值
                    if (!pointStockMap.containsKey(stockPointSkuVO.getStockPointId()) || pointStockMap.get(stockPointSkuVO.getStockPointId()) > pointStock) {
                        pointStockMap.put(stockPointSkuVO.getStockPointId(), pointStock);
                    }
                }
            }
            // 单品的总库存
            for (SkuComboVO skuComboVO : skuComboList) {
                skuComboVO.setStock(stockVOMap.get(skuComboVO.getComboSkuId().toString()).getStock());
            }
            // 累加上sku的所有组合商品的所有仓库的库存最小值,就是当前sku可用的最小库存
            int totalStock = 0;
            boolean isSupplierQuery = Objects.equals(spu.getShopId(), -1L)
                    && !Objects.equals(spu.getSupplierId(), -1L);
            if (isSupplierQuery) {
                int comboStock;
                for (int i=0; i<skuComboList.size(); i++) {
                    comboStock = skuComboList.get(i).getStock() / skuComboList.get(i).getComboCount();
                    if (i == 0) {
                        totalStock = comboStock;
                        continue;
                    }
                    totalStock = Math.min(totalStock, comboStock);
                }
            } else {
                for (Long pointId : pointStockMap.keySet()) {
                    totalStock += pointStockMap.get(pointId);
                }
            }
            sku.setStock(totalStock);
            if(isSupplierSpu){
                sku.setSupplierStock(totalStock);
            }
            sku.setSkuComboList(skuComboList);
            List<Long> skuList = skuComboList.stream().map(SkuComboVO::getComboSkuId).collect(Collectors.toList());
            if (!hasStockBySkuIds(skuList, shopId)) {
                sku.setStock(0);;
            }
        }
    }

    @Override
    public Boolean hasStockBySkuIds(List<Long> comboSkuIds, Long shopId) {
        int totalStock = 0;
        // 当前组合sku拥有的仓库ids
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(comboSkuIds);
        List<SkuAddrVO> skuList = listSpuDetailByIds(comboSkuIds);
        List<SkuAddrVO> virtualSkuList = skuList.stream().filter(skuAddrVO -> Objects.equals(skuAddrVO.getSpuMold(), SpuMold.VIRTUAL.value())).toList();
        WarehouseVO warehouse = warehouseService.getDefaultWarehouseByShopId(shopId,SysTypeEnum.MULTISHOP.value());
        Map<Long, Integer> skuMoldMap = virtualSkuList.stream().collect(Collectors.toMap(SkuAddrVO::getSkuId, SkuAddrVO::getSpuMold));
        long count = virtualSkuList.size();
        // 获取组合sku的区域库存
        Map<String, SkuStockVO> skuStockMap = skuStockService.mapSkuPointStockByStockPoints(stockPointList);
        Map<Long,Integer> pointStockMap = new HashMap<>(stockPointList.size());
        Map<Long, List<StockPointSkuVO>> stockPointMap = stockPointList.stream().collect(Collectors.groupingBy(StockPointSkuVO::getStockPointId));
        // 根据仓库id循环判断
        for (Map.Entry<Long, List<StockPointSkuVO>> entry : stockPointMap.entrySet()) {
            // 当前区域的sku库存信息列表
            List<StockPointSkuVO> skuStockPointList = entry.getValue();
            // 如果当前仓库的所有sku库存为空,或者小于需要查询的sku的数量,表示这些关联的sku没有共同库存跳过即可
            if(skuStockPointList.size() + count < comboSkuIds.size()){
                continue;
            }
            for (StockPointSkuVO stockPointSkuVO : skuStockPointList) {
//                // 如果不是默认仓库且为虚拟商品,直接跳过
//                if(!Objects.equals(warehouse.getWarehouseId(),stockPointSkuVO.getStockPointId()) && skuMoldMap.containsKey(stockPointSkuVO.getSkuId())){
//                    continue;
//                }
                SkuStockVO skuStockVO = skuStockMap.get(StockUtil.skuPointKey(stockPointSkuVO.getSkuId(), stockPointSkuVO.getStockPointId()));
                int pointStock = skuStockVO.getStock();
                // 组合商品的库存取最小值,比如都是默认仓库的情况下,取最小值
                if(!pointStockMap.containsKey(skuStockVO.getStockPointId()) || pointStockMap.get(skuStockVO.getStockPointId()) > pointStock) {
                    pointStockMap.put(skuStockVO.getStockPointId(), pointStock);
                }
            }
        }
        // 累加上sku的所有组合商品的所有仓库的库存最小值,就是当前sku可用的最小库存
        for (Long pointId : pointStockMap.keySet()) {
            totalStock += pointStockMap.get(pointId);
        }
        return totalStock > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStockMode(Long stockPointId, Integer stockMode, Integer type) {
        // 获取门店所有的sku
        List<StockPointSkuVO> pointSkuList = stockPointSkuService.listByPointId(stockPointId);
        UidInfoBO uidInfoBO = AuthUserContext.get();
        if (Objects.nonNull(type)) {
            List<Long> skuIds = pointSkuList.stream().map(StockPointSkuVO::getSkuId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(skuIds)) {
                return;
            }
            // 获取原来的sku库存
            List<SkuStockVO> stockDbList = skuStockService.listSkuStockBySkuIds(pointSkuList);
            Map<Long, Integer> stockMap = stockDbList.stream().filter(skuStockVO -> skuStockVO.getStockPointId() != 0).collect(Collectors.toMap(SkuStockVO::getSkuId, SkuStockVO::getStock));
            pointSkuList.forEach(s-> s.setStock(stockMap.get(s.getSkuId())));
            List<SkuStockVO> deleteList = new ArrayList<>(pointSkuList.size());
            for (StockPointSkuVO skuVO : pointSkuList) {
                SkuStockVO skuStockVO = new SkuStockVO(skuVO.getSkuId(), stockMap.get(skuVO.getSkuId()), skuVO.getStockPointId(), null);
                deleteList.add(skuStockVO);
            }
            if (type == 1) {
                // 添加默认仓库库存
                List<SkuStockVO> updateList = new ArrayList<>(skuIds.size());
                // 获取sku对应的默认仓库
                List<StockPointSkuVO> pointList = stockPointSkuService.listPointBySkuIds(skuIds).stream().filter(stockPointSkuVO -> stockPointSkuVO.getType() == 0).toList();
                // 获取原来的sku库存
                // Map<String, SkuStockVO> skuStockMap = skuStockService.mapSkuPointStockByStockPoints(pointList);
                // 将门店库存添加到默认仓库
                for (StockPointSkuVO pointSkuVO : pointList) {
                    // SkuStockVO skuStock = skuStockMap.get(pointSkuVO.getSkuId() + Constant.UNDERLINE + pointSkuVO.getStockPointId());
                    SkuStockVO skuStockVO = new SkuStockVO(pointSkuVO.getSkuId(), stockMap.get(pointSkuVO.getSkuId()), pointSkuVO.getStockPointId(), null);
                    updateList.add(skuStockVO);
                }
                stockManager.skuStock(updateList, LuaOperateEnum.SKU_ADD);
            }
            stockManager.skuStock(deleteList, LuaOperateEnum.SKU_SUB);
            List<StockBillLogItemDTO> stockBillLogItemDTOList = new ArrayList<>();
            Long shopId = uidInfoBO.getTenantId();
            List<SkuVO> skuVOS = skuMapper.listSkuBySkuIds(skuIds);
            stockBillLogItemDTOList.addAll(addBillLogList(StockBillType.SWITCH_STATION.value(), StockType.OUT_OF_STOCK.value(), pointSkuList, skuVOS, shopId, null));
            if (type == 1) {
                // 获取默认仓库
                WarehouseVO warehouse = warehouseService.getDefaultWarehouseByShopId(shopId, uidInfoBO.getSysType());
                if (Objects.isNull(warehouse)) {
                    throw new LuckException("找不到该店铺的默认仓库");
                }
                stockBillLogItemDTOList.addAll(addBillLogList(StockBillType.SWITCH_WAREHOUSE.value(), StockType.WAREHOUSING.value(), pointSkuList, skuVOS, shopId, warehouse.getWarehouseId()));
            }
            //发送事件进行添加商品库存模式转换出入库记录
            SendStatus sendStockStatus = stockBillLogTemplate.syncSend(RocketMqConstant.STOCK_BILL_LOG_TOPIC, new GenericMessage<>(stockBillLogItemDTOList)).getSendStatus();
            if (!Objects.equals(sendStockStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }
        List<Long> stockPointSkuIds = pointSkuList.stream().map(StockPointSkuVO::getStockPointSkuId).collect(Collectors.toList());
        stockPointSkuService.batchDeleteByStockPointSkuIdList(stockPointSkuIds);
        List<Long> spuIds = pointSkuList.stream().map(StockPointSkuVO::getSpuId).collect(Collectors.toList());
        removeCacheSkuWithAttrBySpuId(spuIds);
        warehouseService.removeWarehouseCache(stockPointId, uidInfoBO.getTenantId(), uidInfoBO.getSysType());
    }

    @Override
    public void loadSeckillStockBillLogItems(Long spuId, List<StockPointSkuDTO> filtePointList) {
        List<Long> skuIds = filtePointList.stream().map(StockPointSkuDTO::getSkuId).collect(Collectors.toList());
        List<SkuDTO> skuDTOS = BeanUtil.mapAsList(listSkuAndStockBySkuIds(skuIds), SkuDTO.class);
        Map<Long, List<StockPointSkuDTO>> skuStockMap = filtePointList.stream().collect(Collectors.groupingBy(StockPointSkuDTO::getSkuId));

        skuDTOS.forEach(s-> s.setStockPointList(skuStockMap.get(s.getSkuId())));
        List<StockBillLogItemDTO> stockBillLogItemDTOList =  loadStockBillLogItems(StockType.WAREHOUSING.value(), StockBillType.SECKILL_STOCK.value(), spuId, skuDTOS);
        // 发送事件进行添加商品入库记录
        SendStatus sendStockStatus = stockBillLogTemplate.syncSend(RocketMqConstant.STOCK_BILL_LOG_TOPIC, new GenericMessage<>(stockBillLogItemDTOList)).getSendStatus();
        if (!Objects.equals(sendStockStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    public int countNormalSkuBySkuIds(Set<Long> skuIds) {
        return skuMapper.countNormalSkuBySkuIds(skuIds);
    }

    @Override
    public void removeCacheSkuWithAttrBySpuId(List<Long> spuIdList) {
        if (CollUtil.isEmpty(spuIdList)) {
            return;
        }
        for (Long spuId : spuIdList) {
            RedisUtil.del(CacheNames.SKU_WITH_ATTR_LIST_KEY + CacheNames.UNION + spuId);
        }
    }

    List<StockBillLogItemDTO> addBillLogList(int stockBillType, int stockType, List<StockPointSkuVO> stockPointSkuVOList, List<SkuVO> skuVOS, Long shopId, Long stockPointId) {
        List<StockBillLogItemDTO> stockBillLogItems = new ArrayList<>(stockPointSkuVOList.size());
        Map<Long, SkuVO> skuMap = skuVOS.stream().collect(Collectors.toMap(SkuVO::getSkuId, s -> s));
        Long userId = AuthUserContext.get().getUserId();
        Integer sysType = AuthUserContext.get().getSysType();
        String userPhone;
        if (sysType.equals(SysTypeEnum.MULTISHOP.value())) {
            ServerResponseEntity<ShopUserVO> userResponse = shopUserFeignClient.getByUserId(userId);
            if (!userResponse.isSuccess() || userResponse.getData() == null) {
                throw new LuckException("无法获取制单人手机号");
            }
            userPhone = userResponse.getData().getPhone();
        } else {
            ServerResponseEntity<SupplierApiUserVO> supplierResponse = supplierUserFeignClient.getByUserId(userId);
            if (!supplierResponse.isSuccess() || supplierResponse.getData() == null) {
                throw new LuckException("无法获取制单人手机号");
            }
            userPhone = supplierResponse.getData().getPhone();
        }
        stockPointSkuVOList.forEach(s -> {
            SkuVO sku = skuMap.get(s.getSkuId());
            StockBillLogItemDTO stockBillLogItem = new StockBillLogItemDTO(
                    s.getSpuId(),
                    s.getSkuId(),
                    shopId,
                    null,
                    sku.getSpuName(),
                    sku.getSkuName(),
                    s.getStock(),
                    sku.getPriceFee(),
                    sku.getPartyCode(),
                    sku.getMainImgUrl()
            );
            stockBillLogItem.setAfterStock(0);
            stockBillLogItem.setSupplierDeliveryType(SupplierDeliveryType.SHOP_DELIVERY.value());
            stockBillLogItem.setSupplierId(null);
            stockBillLogItem.setCreateTime(new Date());
            stockBillLogItem.setUpdateTime(new Date());
            stockBillLogItem.setStockBillType(stockBillType);
            stockBillLogItem.setStocktype(stockType);
            stockBillLogItem.setStockPointId(stockPointId == null ? s.getStockPointId() : stockPointId);
            stockBillLogItem.setStockPointType(stockPointId == null ? s.getStockPointType() : StockPointType.WAREHOUSE.getValue());
            stockBillLogItem.setMakerMobile(userPhone);
            if (sysType.equals(SysTypeEnum.SUPPLIER.value())) {
                stockBillLogItem.setSupplierId(shopId);
                stockBillLogItem.setShopId(-1L);
            }
            stockBillLogItems.add(stockBillLogItem);
        });
        return stockBillLogItems;
    }

    /**
     * 检查供应商sku信息是否变更
     * @param sku 新sku
     * @param dbSku 原sku
     * @return 是否变更
     */
    private boolean checkSupplierSkuMsgChange(SkuDTO sku, SkuVO dbSku) {
        // 检验'供货价'变化
        boolean isChange = !(Objects.isNull(sku.getPriceFee()) || Objects.equals(sku.getPriceFee(), dbSku.getPriceFee()));
        // 检验'市场价'变化
        isChange = isChange
                || !(Objects.isNull(sku.getMarketPriceFee()) || Objects.equals(sku.getMarketPriceFee(), dbSku.getMarketPriceFee()));
        // 检验'体积'变化
        isChange = isChange
                || !(Objects.isNull(sku.getVolume()) || Objects.equals(sku.getVolume(), dbSku.getVolume().doubleValue()));
        // 校验'重量'变化
        isChange = isChange
                || !(Objects.isNull(sku.getWeight()) || Objects.equals(sku.getWeight(), dbSku.getWeight().doubleValue()));
        // 检验'sku编码'变化
        isChange = isChange
                || !(Objects.isNull(sku.getPartyCode()) || Objects.equals(sku.getPartyCode(), dbSku.getPartyCode()));
        return isChange;
    }
}
