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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.common.order.constant.StockModeEnum;
import com.tmerclub.cloud.common.order.vo.WarehouseVO;
import com.tmerclub.cloud.api.feign.SearchSpuFeignClient;
import com.tmerclub.cloud.api.order.feign.PurchaseOrderFeignClient;
import com.tmerclub.cloud.api.product.vo.SkuStockVO;
import com.tmerclub.cloud.common.cache.constant.CacheNames;
import com.tmerclub.cloud.common.cache.constant.LuaOperateEnum;
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.constant.SysTypeEnum;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.product.constant.*;
import com.tmerclub.cloud.common.product.dto.SkuDTO;
import com.tmerclub.cloud.common.product.dto.StockPointSkuDTO;
import com.tmerclub.cloud.common.product.vo.*;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.api.product.dto.WarehouseDTO;
import com.tmerclub.cloud.product.manager.StockManager;
import com.tmerclub.cloud.product.mapper.SkuMapper;
import com.tmerclub.cloud.product.mapper.SpuMapper;
import com.tmerclub.cloud.product.model.SkuStock;
import com.tmerclub.cloud.product.service.*;
import com.tmerclub.cloud.product.service.*;
import com.tmerclub.cloud.product.util.StockUtil;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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

/**
 * 库存信息
 *
 * @author tmerclub
 * @date 2020-10-28 15:27:24
 */
@Service
public class SkuStockServiceImpl implements SkuStockService {

    private static final Logger log = LoggerFactory.getLogger(SkuStockServiceImpl.class);


    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private StockManager stockManager;

    @Autowired
    private StockBillLogService stockBillLogService;

    @Autowired
    private SearchSpuFeignClient searchSpuFeignClient;

    @DubboReference
    private PurchaseOrderFeignClient purchaseOrderFeignClient;
    @Autowired
    private WarehouseService warehouseService;

    @Autowired
    private StockPointSkuService stockPointSkuService;

    @Autowired
    private SkuComboService skuComboService;

    @Override
    public void batchSave(List<SkuStockVO> skuStocks, Integer spuStatus) {
        // 拼接sku库存集合
        Map<String, String> skuStockMap = new HashMap<>(skuStocks.size());
        // mset 批量插入sku库存数据
        for (SkuStockVO skuStock : skuStocks) {
            String stockInfo = skuStock.getStock() + Constant.UNDERLINE + skuStock.getLockStock() + Constant.UNDERLINE + skuStock.getSale();
            skuStockMap.put(StockUtil.getSkuStockKey(skuStock.getSkuId(), skuStock.getStockPointId(), skuStock.getStockPointType()), stockInfo);
            // dev
//            String stockInfo = skuStock.getStock() + Constant.UNDERLINE + skuStock.getLockStock() + Constant.UNDERLINE + skuStock.getSale() + Constant.UNDERLINE + spuStatus;
//            skuStockMap.put(StockUtil.getSkuStockKey(skuStock.getSkuId()), stockInfo);

        }
        stockManager.mSet(skuStockMap);
    }

    @Override
    public void updateBatch(List<SkuDTO> skuList) {
        if (CollUtil.isEmpty(skuList)) {
            return;
        }
        List<StockPointSkuDTO> stockPointSkuDTOS = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List <SkuStockVO> skuStockVOList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (SkuDTO sku : skuList) {
            if (Objects.nonNull(sku.getChangeStock())) {
                sku.getStockPointList().forEach(s-> {
                    s.setSkuId(sku.getSkuId());
                    s.setSpuId(sku.getSpuId());
                    s.setStatus(sku.getStatus());
                });
                stockPointSkuDTOS.addAll(sku.getStockPointList());
                for (StockPointSkuDTO stockPointSkuDTO : sku.getStockPointList()) {
//                    if (stockPointSkuDTO.getStock() == 0 ) {
//                        list.add(CacheNames.SKU_SOCK + stockPointSkuDTO.getSkuId() + StrUtil.C_UNDERLINE + stockPointSkuDTO.getStockPointId());
//                        continue;
//                    }
                    SkuStockVO stockVO = new SkuStockVO(stockPointSkuDTO.getSkuId(), stockPointSkuDTO.getStock(), stockPointSkuDTO.getStockPointId(), stockPointSkuDTO.getStockPointType());
                    stockVO.setStatus(sku.getStatus());
                    stockVO.setSpuId(sku.getSpuId());
                    skuStockVOList.add(stockVO);
                }
//                list.add(StockUtil.loadQueryArray(
//                        sku.getSkuId(),
//                        StockManager.WAREHOUSE_ID,
//                        sku.getChangeStock(),
//                        sku.getChangeStock() > 0 ? StockUtil.ADD : StockUtil.SUBTRACT)
//                );
            }
        }
//        if (true) {
        if (CollUtil.isEmpty(skuStockVOList)) {
            return;
        }
        // 修改关联数据
        stockPointSkuService.changeStockPoint(stockPointSkuDTOS, true);
        Long spuId = skuStockVOList.get(0).getSpuId();
        handSkuStock(spuId, skuStockVOList, LuaOperateEnum.SKU_REPLACE, true);
        // 更新库存
        // String stock = stockManager.skuStock(skuStockVOList, LuaOperateEnum.SKU_REPLACE);
        // 返回skuId代表库存改变失败
//        if (!stock.contains(Constant.UNDERLINE)) {
//            throw new LuckException("sku库存发生改变，请刷新后重试");
//        }
        //stockManager.mDel(list);
    }

    @Override
    public Map<String, SkuStockVO> listStockBySpuId(Long spuId) {
        List<Long> skuIds = skuMapper.listSkuIdBySpuId(spuId);
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(skuIds);
        return this.mapSkuPointStockByStockPoints(stockPointList);
    }

    @Override
    public List<SkuVO> listSkuStockBySupplierSpuIds(List<Long> spuIds, Long shopId) {
        List<SkuVO> skuList = skuMapper.listSupplierSkuIdBySpuId(spuIds, shopId);
        return skuList;
    }

    @Override
    public SkuStock getBySkuId(Long skuId, Integer spuMold) {
        // 获取sku总库存
        SkuStockVO skuStockVO = stockManager.getSkuTotalStock(skuId);
        int stock = skuStockVO.getStock();
        if(Objects.equals(spuMold, SpuMold.COMBO.value())){
            List<SkuStockVO> comboStocks = getComboSpuStockBySkuIds(Collections.singletonList(skuId));
            stock = CollectionUtil.isEmpty(comboStocks) ? 0: comboStocks.get(0).getStock();
        }
        return new SkuStock(skuId, stock, skuStockVO.getLockStock());
    }
    @Override
    public Map<Long, Integer> spuStockMapBySpuIds(List<Long> spuIds) {
        List<SkuVO> skuList = skuMapper.listSimpleSkuBySpuIds(spuIds);
        if (CollUtil.isEmpty(skuList)) {
            return Collections.emptyMap();
        }
        List<Long> skuIds = skuList.stream().map(SkuVO::getSkuId).collect(Collectors.toList());
        Map<Long, SkuStockVO> stockVOMap = this.mapSkuTotalStockBySkuIds(skuIds);
        Map<Long, List<SkuVO>> spuMap = skuList.stream().collect(Collectors.groupingBy(SkuVO::getSpuId));
        Map<Long, Integer> spuStockMap = new HashMap<>(spuMap.size());
        for (Map.Entry<Long, List<SkuVO>> entry : spuMap.entrySet()) {
            int stock = 0;
            for (SkuVO skuVO : entry.getValue()) {
                SkuStockVO skuStockVO = stockVOMap.get(skuVO.getSkuId());
                stock += skuStockVO.getStock();
            }
            spuStockMap.put(entry.getKey(), stock);
        }
        return spuStockMap;
    }

    @Override
    public List<SkuVO> listShopStockByPartyCodesAndShopId(List<String> partyCodes, Long shopId) {
        if (CollectionUtils.isEmpty(partyCodes)) {
            return new ArrayList<>(0);
        }
        // 根据商品编码获取skuId列表
        List<SkuVO> skuList = skuMapper.listSkuIdByPartyCodesAndShopId(partyCodes, shopId);
        if (CollUtil.isEmpty(skuList)) {
            return Collections.emptyList();
        }
        List<Long> skuIds = skuList.stream().map(SkuVO::getSkuId).collect(Collectors.toList());
        Map<Long, SkuStockVO> skuStockMap = this.mapSkuTotalStockBySkuIds(skuIds);
        for (SkuVO skuVO : skuList) {
            if (!skuStockMap.containsKey(skuVO.getSkuId())) {
                continue;
            }
            skuVO.setStock(skuStockMap.get(skuVO.getSkuId()).getStock());
        }
        return skuList;
    }

    @Override
    public List<SkuStockVO> listSkuStockBySkuIds(List<StockPointSkuVO> stockPointIdList) {
        return stockManager.convertSkuStock(stockPointIdList);
    }

    @Override
    public Map<Long, SkuStockVO> mapSkuTotalStockBySkuIds(List<Long> skuIds) {
        return stockManager.mapSkuTotalStock(skuIds);
    }

    @Override
    public Map<String, SkuStockVO> mapSkuPointStockByStockPoints(List<StockPointSkuVO> stockPointSkuList) {
        return stockManager.skuStockMap(stockPointSkuList);
    }

    @Override
    public Map<String, SkuStockVO> mapSkuTotalStockAndPointStock(List<StockPointSkuVO> stockPointSkuList) {
        Set<Long> skuIdSet = stockPointSkuList.stream().map(StockPointSkuVO::getSkuId).collect(Collectors.toSet());
        for (Long skuId : skuIdSet) {
            StockPointSkuVO stockPointSkuVO = new StockPointSkuVO();
            stockPointSkuVO.setSkuId(skuId);
            stockPointSkuVO.setStockPointId(Constant.ZERO_LONG);
            stockPointSkuList.add(stockPointSkuVO);
        }
        return stockManager.skuStockMap(stockPointSkuList);
    }

    @Override
    public Map<String, SkuStockVO> skuStockMapBySkuIds(List<Long> skuIds) {
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(skuIds);
        return stockManager.skuStockMap(stockPointList);
    }

    @Override
    public void handleSkuStockChange() {
        // 从redis中获取上次执行的时间，如果没有则默认为统计所有数据
        Date data = RedisUtil.get(CacheNames.SKU_CHANGE_STATISTICS_TIME);
        // 当前时间
        Date currentTime = new Date();
        // 查询出入库记录，返回发生过库存变化的商品id
        if (Objects.nonNull(data)) {
            data = DateUtil.offsetSecond(data, -10);
        }
        List<Long> stockSpuIds = stockBillLogService.listSpuIdOfStockChange(data, currentTime);
        // 采购订单记录
        ServerResponseEntity<List<Long>> purchaseResponse = purchaseOrderFeignClient.listSpuIdOfStockChange(data, currentTime);
        if (!purchaseResponse.isSuccess()) {
            throw new LuckException(purchaseResponse.getMsg());
        }
        List<Long> purchaseSpuIds = purchaseResponse.getData();
        if (CollUtil.isEmpty(stockSpuIds) && CollUtil.isEmpty(purchaseSpuIds)) {
            return;
        }
        Set<Long> spuIdsSet = new HashSet<>(Constant.INITIAL_CAPACITY);
        spuIdsSet.addAll(stockSpuIds);
        spuIdsSet.addAll(purchaseSpuIds);
        List<Long> spuIds = new ArrayList<>(spuIdsSet);
        List<SpuVO> spuDbList = spuMapper.listSpuDetailBySpuIds(spuIds);
        List<Long> supplierSpuIds = new ArrayList<>();
        for (SpuVO spuVO : spuDbList) {
            if (Objects.equals(spuVO.getSupplierSpuType(), SupplierSpuType.YES.value())) {
                // 供应商商品id
                supplierSpuIds.add(spuVO.getSpuId());
            }
        }

        // 通过商品id查询商品下的skuId列表
        List<SkuVO> skuList = skuMapper.listSimpleSkuBySpuIds(spuIds);
        List<Long> skuIds = skuList.stream().map(SkuVO::getSkuId).collect(Collectors.toList());
        Map<Long, List<SkuVO>> spuMap = skuList.stream().collect(Collectors.groupingBy(SkuVO::getSpuId));
        // 获取sku总库存
        Map<Long, SkuStockVO> skuStockMap = this.mapSkuTotalStockBySkuIds(skuIds);
        List<SpuVO> spuList = new ArrayList<>(spuIds.size());
        Map<Long, SpuVO> supplierSpuMap = new HashMap<>();
        // 根据spuId获取商品sku的总库存和总销量
        for (SpuVO spuDb : spuDbList) {
            List<SkuVO> skuVOList;
            if (Objects.equals(spuDb.getSupplierSpuType(), SupplierSpuType.CONSIGNMENT.value()) &&
                    Objects.equals(spuDb.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
                skuVOList = spuMap.get(spuDb.getSupplierSpuId());
            } else {
                skuVOList = spuMap.get(spuDb.getSpuId());
            }
            if (CollUtil.isEmpty(skuVOList)) {
                continue;
            }
            SpuVO spuVO = new SpuVO();
            spuVO.setStockWarning(0);
            int saleNum = 0;
            int stock = 0;
            for (SkuVO skuVO : skuVOList) {
                if (!skuStockMap.containsKey(skuVO.getSkuId())) {
                    continue;
                }
                SkuStockVO skuStockVO = skuStockMap.get(skuVO.getSkuId());
                // 统计es商品的总销量和总库存
                saleNum += skuStockVO.getSale();
                stock += skuStockVO.getStock();
                // 用于库存预警
                skuVO.setStock(skuStockVO.getStock());
                if (skuVO.getStockWarning() >= skuStockVO.getStock() && Objects.equals(spuVO.getStockWarning(), Constant.ZERO_INTEGER)) {
                    spuVO.setStockWarning(1);
                }
            }

            spuVO.setSpuId(spuDb.getSpuId());
            spuVO.setSaleNum(saleNum);
            spuVO.setTotalStock(stock);
            if (supplierSpuIds.contains(spuVO.getSpuId())) {
                supplierSpuMap.put(spuVO.getSpuId(), spuVO);
            }
            spuList.add(spuVO);
        }
        // 代销商品同步供应商商品库存
        if (CollUtil.isNotEmpty(supplierSpuIds)) {
            List<SpuVO> spuIdList = spuMapper.batchSupListBySupplierId(supplierSpuIds);
            for (SpuVO spuVO : spuIdList) {
                if (!Objects.equals(spuVO.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value()) || !supplierSpuMap.containsKey(spuVO.getSupplierSpuId())) {
                    continue;
                }
                SpuVO supplierSpu = supplierSpuMap.get(spuVO.getSupplierSpuId());
                SpuVO spu = BeanUtil.map(supplierSpu, SpuVO.class);
                spu.setSpuId(spuVO.getSpuId());
                spuList.add(spu);
            }
        }

        // 更新es中的商品库存、销量数据
        searchSpuFeignClient.batchUpdateStockAndSaleNum(spuList);

        // 查询sku预警数量，并更新sku预警信息
        skuMapper.batchUpdateSkuWarning(skuList);
        // 更新redis中的最后一次执行时间
        RedisUtil.set(CacheNames.SKU_CHANGE_STATISTICS_TIME, currentTime, Constant.DAY_SECOND);
    }

    @Override
    public void initSkuStock() {
        int index = 0;
        // mset数量定为50， 数量太大redis性能衰减
        int size = 100;
        boolean hasNext = true;

        List<SkuVO> skuList = skuMapper.listAll();
        Map<Long, Integer> skuMap = skuList.stream().collect(Collectors.toMap(SkuVO::getSkuId, SkuVO::getStatus));


        while (index < skuList.size()) {
            int toIndex = size + index;
            if (toIndex > skuList.size()) {
                toIndex = skuList.size();
            }
            List<SkuVO> skus = skuList.subList(index, toIndex);
            List<Long> skuIds = skus.stream().map(SkuVO::getSkuId).toList();

            Map<Long, Integer> stockDbMap = new HashMap<>(0);
            try {
                // 查询sku库存
                List<SkuStock> skuStocks = skuMapper.listSkuStock(skuIds);
                stockDbMap = skuStocks.stream().collect(Collectors.toMap(SkuStock::getSkuId, SkuStock::getStock));
            } catch (Exception e) {
                log.error("获取sku库存异常", e);
            }

            Map<Long, SkuStockVO> skuStockMap = stockManager.mapSkuTotalStock(skuIds);
            Map<String, String> map = new HashMap<>(135);
            // 拼接key和value
            for (SkuVO skuVO : skus) {
                String stock = "0";
                SkuStockVO skuStockVO = new SkuStockVO(skuVO.getSkuId(), 0, 0, 0, 0L);
                skuStockVO.setZoneNo(Constant.ZERO_INTEGER);
                SkuStockVO skuStock = skuStockMap.get(skuVO.getSkuId());
                if (Objects.nonNull(skuStock)) {
                    skuStockVO.setStock(skuStock.getStock());
                    if (Objects.nonNull(skuStockVO.getLockStock())) {
                        skuStockVO.setLockStock(skuStock.getLockStock());
                    }
                    if (Objects.nonNull(skuStockVO.getSale())) {
                        skuStockVO.setSale(skuStock.getSale());
                    }
                } else if (stockDbMap.containsKey(skuVO.getSkuId())) {
                    skuStockVO.setStock(stockDbMap.get(skuVO.getSkuId()));
                }

                Integer status = 0;
                if (Objects.equals(skuMap.get(skuVO.getSkuId()), StatusEnum.ENABLE.value())) {
                    status =  StatusEnum.ENABLE.value();
                }
                String key = CacheNames.SKU_SOCK + StockManager.WAREHOUSE_ID + StrUtil.C_UNDERLINE + skuVO.getSkuId();
                String value = skuStockVO.getStock().toString() +
                        StrUtil.C_UNDERLINE +
                        skuStockVO.getLockStock() +
                        StrUtil.C_UNDERLINE +
                        skuStockVO.getSale() +
                        StrUtil.C_UNDERLINE + status;
                map.put(key, value);
            }
            // 批量插入 mset
            stockManager.mSet(map);
            index += size;
        }
    }

    @Override
    public void initPointStock() {
        int index = 0;
        // mset数量定为50， 数量太大redis性能衰减
        int size = 100;

        List<SkuVO> skuList = skuMapper.listAll();

        while (index < skuList.size()) {
            int toIndex = size + index;
            if (toIndex > skuList.size()) {
                toIndex = skuList.size();
            }
            List<SkuVO> skus = skuList.subList(index, toIndex);
            List<Long> skuIds = skus.stream().map(SkuVO::getSkuId).toList();

            List<StockPointSkuVO> stockPointSkuList = stockPointSkuService.listBySkuIds(skuIds);
            Map<Long, List<StockPointSkuVO>> pointMap = stockPointSkuList.stream().collect(Collectors.groupingBy(StockPointSkuVO::getSkuId));
            List<SkuStockVO> skuStockList = new ArrayList<>(Constant.INITIAL_CAPACITY);
            List<StockPointSkuVO> stockPointSkus = new ArrayList<>();
            for (Map.Entry<Long, List<StockPointSkuVO>> entry : pointMap.entrySet()) {
                stockPointSkus.addAll(entry.getValue());
            }

            // 查询旧的库存格式
            Map<String, String> oldStockMap = stockManager.scan(CacheNames.SKU_SOCK + Constant.ZERO_INTEGER + Constant.UNDERLINE);

            Map<String, SkuStockVO> skuStockMap = this.mapSkuTotalStockAndPointStock(stockPointSkus);
            Map<String, String> map = new HashMap<>(135);
            // 拼接key和value
            for (SkuVO skuVO : skus) {
                // 已删除的sku不用初始化库存
                if (Objects.equals(skuVO.getStatus(), StatusEnum.DELETE.value())) {
                    continue;
                }
                // 总库存
                SkuStockVO skuStock = skuStockMap.get(skuVO.getSkuId().toString());
                int stock = 0;
                int lockStock = 0;
                int sale = 0;
                int status = 0;
                if (Objects.equals(skuVO.getStatus(), StatusEnum.ENABLE.value())) {
                    status =  StatusEnum.ENABLE.value();
                }

                if (!pointMap.containsKey(skuVO.getSkuId())) {
                    continue;
                }

                List<StockPointSkuVO> stockPointSkuVOList = pointMap.get(skuVO.getSkuId());
                for (StockPointSkuVO stockPointSkuVO : stockPointSkuVOList) {
                    if (stockPointSkuVO.getStatus() == -1) {
                        continue;
                    }
                    int pointStatus = status;
                    SkuStockVO skuPointStock = new SkuStockVO(skuVO.getSkuId(), 0, 0, 0, stockPointSkuVO.getStockPointId());

                    // 默认仓库、库存未初始化
                    if (Objects.equals(stockPointSkuVO.getType(), 0) && oldStockMap.containsKey(CacheNames.SKU_SOCK + Constant.ZERO_INTEGER + Constant.UNDERLINE + skuVO.getSkuId())) {
                        String stockStr = oldStockMap.get(CacheNames.SKU_SOCK + Constant.ZERO_INTEGER + Constant.UNDERLINE + skuVO.getSkuId());
                        String[] split = stockStr.split(Constant.UNDERLINE);
                        for (int i = 0; i < split.length; i++) {
                            Integer num = 0;
                            if (StrUtil.isNotBlank(split[i]) && !StrUtil.equals(split[i], "null")) {
                                num = Integer.parseInt(split[i]);
                            }
                            switch (i) {
                                case 0 -> skuPointStock.setStock(num);
                                case 1 -> skuPointStock.setLockStock(num);
                                case 2 -> skuPointStock.setSale(num);
                                default -> {}
                            }
                        }
                        skuStockList.add(skuPointStock);
                    } else {
                        SkuStockVO skuStockPoint = skuStockMap.get(StockUtil.skuPointKey(skuVO.getSkuId(), stockPointSkuVO.getStockPointId()));
                        if (Objects.nonNull(skuStockPoint) && !Objects.equals(skuStock.getStatus(), StatusEnum.DELETE.value())) {
                            if (status > 0 && Objects.equals(stockPointSkuVO.getStockMode(), StockModeEnum.ALL_STOCK.value())) {
                                pointStatus = 0;
                            }
                            skuPointStock.setStock(skuStockPoint.getStock());
                            if (Objects.nonNull(skuStockPoint.getLockStock())) {
                                skuPointStock.setLockStock(skuStockPoint.getLockStock());
                            }
                            if (Objects.nonNull(skuStockPoint.getSale())) {
                                skuPointStock.setSale(skuStockPoint.getSale());
                            }
                        }
                        if (Objects.isNull(skuStockPoint.getStatus()) || Objects.equals(skuStockPoint.getStatus(), StatusEnum.DELETE.value())) {
                            skuStockList.add(skuPointStock);
                        }
                    }
                    skuPointStock.setStatus(pointStatus);
                    lockStock += skuPointStock.getLockStock();
                    sale += skuPointStock.getSale();
                    stock = stock + skuPointStock.getStock();
                }

                skuStock = new SkuStockVO(skuVO.getSkuId(), stock, lockStock, sale, 0L);
                skuStock.setStatus(status);
                skuStockList.add(skuStock);
            }
            for (SkuStockVO skuStockVO : skuStockList) {
                    String key = CacheNames.SKU_SOCK + skuStockVO.getSkuId();
                    if (skuStockVO.getStockPointId() > 0) {
                        key = key + StrUtil.C_UNDERLINE + skuStockVO.getStockPointId();
                    }
                    String value = skuStockVO.getStock().toString() +
                            StrUtil.C_UNDERLINE +
                            skuStockVO.getLockStock() +
                            StrUtil.C_UNDERLINE +
                            skuStockVO.getSale() +
                            StrUtil.C_UNDERLINE + skuStockVO.getStatus();
                    map.put(key, value);
            }
            if (MapUtil.isNotEmpty(map)) {
                // 批量插入 mset
                stockManager.mSet(map);
            }
            List<String> deleteKeys = new ArrayList<>(skuIds.size());
            for (Long skuId : skuIds) {
                deleteKeys.add(CacheNames.SKU_SOCK + Constant.ZERO_INTEGER + Constant.UNDERLINE + skuId);
            }
            stockManager.mDel(deleteKeys);

            index += size;
        }
    }


    @Override
    public void changeSkuStatus(List<SkuStockVO> skuStockList) {
        stockManager.changeSkuStatus(skuStockList);

    }

    /**
     * 处理一下库存关联商品数据，分别计算新增，修改，删除
     * @param skuStockList
     * @param spuId
     * @param luaOperateEnum 区分修改的添加还是替换
     */
    @Override
    public void handSkuStock(Long spuId, List<SkuStockVO> skuStockList, LuaOperateEnum luaOperateEnum, Boolean hasUserPickUp) {
        // 获取之前的关联数据
        List<Long> skuIds = skuMapper.listSkuIdBySpuId(spuId);
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(skuIds);
        Map<String, SkuStockVO> skuStockMap =  this.mapSkuPointStockByStockPoints(stockPointList);

        Long deafultId = warehouseService.getDefaultWarehouseByShopId(AuthUserContext.get().getTenantId(), AuthUserContext.get().getSysType()).getWarehouseId();
        List<SkuStockVO> updateList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<SkuStockVO> deleteKey = new ArrayList<>(Constant.INITIAL_CAPACITY);
        // 需要删除的关联库存点
        List<Long> deleteSkuIds = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (SkuStockVO skuStockVO : skuStockList) {
            String key = StockUtil.skuPointKey(skuStockVO.getSkuId(), skuStockVO.getStockPointId());
            SkuStockVO skuStockRb = skuStockMap.remove(key);
            if (skuStockVO.getStockPointId() == 0) {
                // 总库存不需要修改
                continue;
            }
            // 获取数据的时候将sku中包含的库存删掉，剩下不包含在列表中的库存就是要删除的
            if (!skuStockVO.getStockPointId().equals(deafultId) && (skuStockVO.getStock() == 0 || skuStockVO.getStock() == null)) {
                //deleteKey.add(StockUtil.skuPointKey(skuStockVO.getSkuId(), skuStockVO.getStockPointId()));
                deleteKey.add(new SkuStockVO(skuStockVO.getSkuId(), 0, skuStockVO.getStockPointId(), null));
                continue;
            }
            if (Objects.isNull(skuStockRb) || Objects.equals(skuStockRb.getStatus(), StatusEnum.DELETE.value())) {
                // 插入
                skuStockVO.setStatus(StatusEnum.ENABLE.value());
                skuStockVO.setOperateType(LuaOperateEnum.SKU_INSERT.value());
                updateList.add(skuStockVO);
            } else {
                // 更新
                skuStockVO.setOperateType(luaOperateEnum.value());
                updateList.add(skuStockVO);
            }
        }
        // 此处都是sku库存列表中没有包含的区域库存信息，全部删除 - 不要用stockManager.mDel()去删，用lua脚本，不然sku总库存数量不会同步更改
        for (Map.Entry<String, SkuStockVO> entry : skuStockMap.entrySet()) {
            SkuStockVO skuStockVO = entry.getValue();
            // deleteKey.add(StockUtil.skuPointKey(skuStockVO.getSkuId(), skuStockVO.getStockPointId()));
            SkuStockVO stockVO = new SkuStockVO(skuStockVO.getSkuId(), skuStockVO.getStock(), skuStockVO.getStockPointId(), null);
            for (StockPointSkuVO pointSkuVO : stockPointList) {
                if (pointSkuVO.getSkuId().equals(skuStockVO.getSkuId()) && pointSkuVO.getStockPointId().equals(skuStockVO.getStockPointId())) {
                    deleteSkuIds.add(pointSkuVO.getStockPointSkuId());
                    stockVO.setStock(0);
                }
            }
            deleteKey.add(stockVO);
        }
        if (CollectionUtil.isNotEmpty(updateList)) {
            String updateStock = stockManager.skuStock(updateList, null);
            if (!updateStock.contains(Constant.UNDERLINE)) {
                throw new LuckException("sku库存发生改变，请刷新后重试");
            }
        }
        if (luaOperateEnum == LuaOperateEnum.SKU_REPLACE) {
            // 如果是新增的话，就不需要删除之前的
            stockManager.skuStock(deleteKey, LuaOperateEnum.SKU_REPLACE);
            stockPointSkuService.batchDeleteByStockPointSkuIdList(deleteSkuIds);
        }
        List<SkuStockVO> statusList = skuStockList.stream().filter(skuStockVO ->
                Objects.nonNull(skuStockVO.getStockPointType()) && skuStockVO.getStockPointType() == StockPointType.STATION.getValue()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(statusList)) {
            return;
        }
        if (hasUserPickUp) {
            statusList.forEach(s-> s.setStatus(1));
        } else {
            // 如果没开启自提，门店库存下架
            statusList.forEach(s-> s.setStatus(0));
        }
        // 门店库存更新一下状态
        String updateStock = stockManager.skuStock(statusList, LuaOperateEnum.SKU_POINT_STATUS);
        if (!updateStock.contains(Constant.UNDERLINE)) {
            throw new LuckException("sku库存发生改变，请刷新后重试");
        }
    }

    @Override
    public void changeSkuStock(List<SkuStockVO> skuStockVOList) {
        if (CollectionUtils.isEmpty(skuStockVOList)) {
            return;
        }
        Set<Long> stockPointIds = new HashSet<>(Constant.INITIAL_CAPACITY);
        Set<Long> skuIds = new HashSet<>(Constant.INITIAL_CAPACITY);
        for (SkuStockVO skuStockVO : skuStockVOList) {
            stockPointIds.add(skuStockVO.getStockPointId());
            skuIds.add(skuStockVO.getSkuId());
        }
        // 查询仓库
        WarehouseDTO warehouseDTO = new WarehouseDTO();
        warehouseDTO.setWarehouseIds(new ArrayList<>(stockPointIds));
        List<WarehouseVO> warehouses = warehouseService.listWarehouse(warehouseDTO);
        if (CollectionUtils.isEmpty(warehouses)) {
            throw new LuckException("仓库不存在");
        }
        Map<Long, WarehouseVO> warehouseMap = warehouses.stream().collect(Collectors.toMap(WarehouseVO::getWarehouseId, x -> x));
        // 查询商品sku
        SkuDTO skuDTO = new SkuDTO();
        skuDTO.setSkuIds(new ArrayList<>(skuIds));
        List<SkuVO> skus = skuMapper.listSku(skuDTO);
        if (CollectionUtils.isEmpty(skus)) {
            return;
        }
        Map<Long, SkuVO> skuMap = skus.stream().collect(Collectors.toMap(SkuVO::getSkuId, x -> x));
        // 查询redis区域库存
        Map<String, SkuStockVO> skuStockMap = stockManager.mapSkuStockBySkuStocks(skuStockVOList);
        // 查询仓库与商品关联（转成Map，key格式为：skuId_stockPointId）
        StockPointSkuDTO stockPointSkuDTO = new StockPointSkuDTO();
        stockPointSkuDTO.setSkuIds(new ArrayList<>(skuIds));
        stockPointSkuDTO.setStockPointIds(new ArrayList<>(stockPointIds));
        List<StockPointSkuVO> stockPointSkus = stockPointSkuService.listStockPointSku(stockPointSkuDTO);
        Map<String, StockPointSkuVO> stockPointSkuMap = new HashMap<>(Constant.INITIAL_CAPACITY);
        if (!CollectionUtils.isEmpty(stockPointSkus)) {
            stockPointSkuMap = stockPointSkus.stream().collect(Collectors.toMap(k -> StockUtil.skuPointKey(k.getSkuId(), k.getStockPointId()), v -> v));
        }
        // 找出新增or删除的数据
        List<StockPointSkuDTO> insertData = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<Long> deleteData = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (SkuStockVO skuStockVO : skuStockVOList) {
            WarehouseVO warehouseVO = warehouseMap.get(skuStockVO.getStockPointId());
            if (Objects.isNull(warehouseVO)) {
                throw new LuckException(String.format("仓库[%s]不存在", skuStockVO.getStockPointId()));
            }
            SkuVO skuVO = skuMap.get(skuStockVO.getSkuId());
            if (Objects.isNull(skuVO)) {
                continue;
            }
            String key = StockUtil.skuPointKey(skuStockVO.getSkuId(), skuStockVO.getStockPointId());
            SkuStockVO skuStock = skuStockMap.get(key);
            StockPointSkuVO stockPointSku = stockPointSkuMap.get(key);
            if (Objects.equals(skuStockVO.getOperateType(), LuaOperateEnum.SKU_ADD.value())) {
                // 增加库存 --- 库存不存在，插入redis库存；关联不存在，新增仓库商品关联
                if (Objects.isNull(skuStock)
                        || Objects.equals(skuStock.getStatus(), -1)) {
                    skuStockVO.setOperateType(LuaOperateEnum.SKU_INSERT.value());
                    skuStockVO.setStatus(skuVO.getStatus());
                }
                if (Objects.isNull(stockPointSku)) {
                    stockPointSkuDTO = new StockPointSkuDTO();
                    BeanUtils.copyProperties(skuStockVO, stockPointSkuDTO);
                    stockPointSkuDTO.setStatus(skuVO.getStatus());
                    stockPointSkuDTO.setType(warehouseVO.getType());
                    stockPointSkuDTO.setStockPointType(Objects.equals(warehouseVO.getSysType(), SysTypeEnum.STATION.value()) ? StockPointType.STATION.getValue() : StockPointType.WAREHOUSE.getValue());
                    insertData.add(stockPointSkuDTO);
                }
            } else if (Objects.equals(skuStockVO.getOperateType(), LuaOperateEnum.SKU_SUB.value())){
                // 减少库存 --- 判断库存是否充足；若扣减后库存为0，非默认仓库需要删除仓库商品关联
                if (Objects.isNull(skuStock)
                        || skuStock.getStock() < skuStockVO.getStock()) {
                    throw new LuckException(String.format("仓库[%s]中skuId[%s]库存不足", skuStockVO.getStockPointId(), skuStockVO.getSkuId()));
                }
                if (Objects.equals(skuStock.getStock(), skuStockVO.getStock())
                        && !Objects.equals(warehouseVO.getType(), 0)
                        && !Objects.isNull(stockPointSku)) {
                    deleteData.add(stockPointSku.getStockPointSkuId());
                }
            }
        }
        // 新增仓库商品关联数据
        if (!CollectionUtils.isEmpty(insertData)) {
            log.info("新增仓库商品关联数据");
            stockPointSkuService.batchSave(insertData);
        }
        // 删除仓库商品关联数据
        if (!CollectionUtils.isEmpty(deleteData)) {
            log.info("删除仓库商品关联数据");
            stockPointSkuService.deleteByIds(deleteData);
        }
        // 修改redis库存
        stockManager.skuStock(skuStockVOList, null);
    }

    @Override
    public void addStockPointBySpuId(Long spuId, List<StockPointSkuDTO> stockPointSkuVOList) {
        // 过滤一下已经被删除的仓库和门店或改为共享模式的门店
        List<StockPointSkuDTO> filtePointList = stockPointSkuService.filtePoint(stockPointSkuVOList);
        // 处理关联数据
        stockPointSkuService.changeStockPoint(filtePointList, false);
        // 修改redis缓存
        List<SkuStockVO> skuStockList = new ArrayList<>(filtePointList.size());
        for (StockPointSkuDTO stockPointSku : filtePointList) {
            skuStockList.add(new SkuStockVO(stockPointSku.getSkuId(), stockPointSku.getStock(), null, null, stockPointSku.getStockPointId()));
        }
        handSkuStock(spuId, skuStockList, LuaOperateEnum.SKU_ADD, true);
    }

    public List<SkuStockVO> getComboSpuStockBySkuIds(List<Long> skuIds) {
        List<SkuStockVO> returnStockList = new ArrayList<>();
        List<SkuComboVO> skuComboList = skuComboService.getCombSpusBySkuIds(skuIds);
        if(CollectionUtils.isEmpty(skuComboList)){
            return new ArrayList<>();
        }
        // 获取所有组合的商品库存
        List<Long> comboSkuIds = skuComboList.stream().map(SkuComboVO::getComboSkuId).toList();
        List<StockPointSkuVO> stockPointList = stockPointSkuService.listPointIdsBySkuIds(comboSkuIds);
        // 获取库存
        List<SkuStockVO> skuStockList = listSkuStockBySkuIds(stockPointList);
        Map<Long, List<SkuStockVO>> skuStockMap = skuStockList.stream().collect(Collectors.groupingBy(SkuStockVO::getSkuId));
        Map<Long, List<SkuComboVO>> skuComboMap = skuComboList.stream().collect(Collectors.groupingBy(SkuComboVO::getSkuId));

        for (Long skuId : skuIds) {
            if(!skuComboMap.containsKey(skuId)){
                continue;
            }
            Map<Long,Integer> pointStockMap = new HashMap<>(stockPointList.size());
            List<SkuComboVO> comboSpuList = skuComboMap.get(skuId);
            // 当前sku的组合商品列表
            for (SkuComboVO skuComboVO : comboSpuList) {
                if(!skuStockMap.containsKey(skuComboVO.getComboSkuId())){
                    continue;
                }
                // 当前组合商品的所有仓库库存列表
                List<SkuStockVO> stockList = skuStockMap.get(skuComboVO.getComboSkuId());
                for (SkuStockVO skuStockVO : stockList) {
                    // 如果是0就是总库存
                    if(Objects.equals(skuStockVO.getStockPointId(),StockManager.WAREHOUSE_ID)){
                        skuComboVO.setStock(skuStockVO.getStock());
                        continue;
                    }
                    // 除以组合数量向下取整得出 当前的组合商品-当前仓库 可用库存
                    int pointStock = Math.floorDiv(skuStockVO.getStock() , skuComboVO.getComboCount());
                    // 组合商品的库存取最小值,比如都是默认仓库的情况下,取最小值
                    if(!pointStockMap.containsKey(skuStockVO.getStockPointId()) || pointStockMap.get(skuStockVO.getStockPointId()) > pointStock) {
                        pointStockMap.put(skuStockVO.getStockPointId(), pointStock);
                    }
                }
            }
            // 累加上sku的所有组合商品的所有仓库的库存最小值,就是当前sku可用的最小库存
            int totalStock = 0;
            for (Long pointId : pointStockMap.keySet()) {
                totalStock += pointStockMap.get(pointId);
            }
            returnStockList.add(new SkuStockVO(skuId,totalStock));
        }
        return returnStockList;
    }
}
