package com.yc.ship.module.product.service.productSpu;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.yc.ship.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.yc.ship.framework.mybatis.core.util.MyBatisUtils;
import com.yc.ship.framework.security.core.LoginUser;
import com.yc.ship.framework.security.core.util.SecurityFrameworkUtils;
import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.framework.tenant.core.util.TenantUtils;
import com.yc.ship.module.product.api.dto.ProductSpuRespDTO;
import com.yc.ship.module.product.controller.admin.productSpu.baseRuleVO.ProductBasicRuleRespVO;
import com.yc.ship.module.product.controller.admin.productSpu.checkRuleVO.ProductCheckRuleRespVO;
import com.yc.ship.module.product.controller.admin.productSpu.groupVO.*;
import com.yc.ship.module.product.controller.admin.productSpu.noticeRuleVO.ProductNoticeRuleRespVO;
import com.yc.ship.module.product.controller.admin.productSpu.otherRuleVO.ProductOtherRuleRespVO;
import com.yc.ship.module.product.controller.admin.productSpu.refundRuleVO.ProductRefundRuleRespVO;
import com.yc.ship.module.product.controller.admin.productSpu.saleRuleVO.ProductSaleRuleRespVO;
import com.yc.ship.module.product.controller.admin.productSpu.skuVO.ProductSkuRespVO;
import com.yc.ship.module.product.controller.admin.productSpu.skuVO.ProductSkuSaveReqVO;
import com.yc.ship.module.product.controller.admin.productSpu.spuVO.*;
import com.yc.ship.module.product.controller.admin.productTakeRule.vo.ProductTakeRuleRespVO;
import com.yc.ship.module.product.dal.dataobject.productBase.ProductBaseDO;
import com.yc.ship.module.product.dal.dataobject.productBasicRule.ProductBasicRuleDO;
import com.yc.ship.module.product.dal.dataobject.productCheckRule.ProductCheckRuleDO;
import com.yc.ship.module.product.dal.dataobject.productGroup.ProductGroupDO;
import com.yc.ship.module.product.dal.dataobject.productNoticeRule.ProductNoticeRuleDO;
import com.yc.ship.module.product.dal.dataobject.productOtherRule.ProductOtherRuleDO;
import com.yc.ship.module.product.dal.dataobject.productRefundRule.ProductRefundRuleDO;
import com.yc.ship.module.product.dal.dataobject.productSaleChannel.ProductSaleChannelDO;
import com.yc.ship.module.product.dal.dataobject.productSaleRule.ProductSaleRuleDO;
import com.yc.ship.module.product.dal.dataobject.productSku.ProductSkuDO;
import com.yc.ship.module.product.dal.dataobject.productSpu.ProductSpuDO;
import com.yc.ship.module.product.dal.dataobject.productTakeRule.ProductTakeRuleDO;
import com.yc.ship.module.product.dal.dataobject.spuship.SpuShipDO;
import com.yc.ship.module.product.dal.mysql.productBase.ProductBaseMapper;
import com.yc.ship.module.product.dal.mysql.productBasicRule.ProductBasicRuleMapper;
import com.yc.ship.module.product.dal.mysql.productCheckRule.ProductCheckRuleMapper;
import com.yc.ship.module.product.dal.mysql.productGroup.ProductGroupMapper;
import com.yc.ship.module.product.dal.mysql.productNoticeRule.ProductNoticeRuleMapper;
import com.yc.ship.module.product.dal.mysql.productOtherRule.ProductOtherRuleMapper;
import com.yc.ship.module.product.dal.mysql.productRefundRule.ProductRefundRuleMapper;
import com.yc.ship.module.product.dal.mysql.productSaleChannel.ProductSaleChannelMapper;
import com.yc.ship.module.product.dal.mysql.productSaleRule.ProductSaleRuleMapper;
import com.yc.ship.module.product.dal.mysql.productSku.ProductSkuMapper;
import com.yc.ship.module.product.dal.mysql.productSpu.ProductSpuMapper;
import com.yc.ship.module.product.dal.mysql.productTakeRule.ProductTakeRuleMapper;
import com.yc.ship.module.product.dal.mysql.spuship.SpuShipMapper;
import com.yc.ship.module.product.enums.SpecTypeEnum;
import com.yc.ship.module.product.service.productGroup.ProductGroupService;
import com.yc.ship.module.resource.controller.admin.category.vo.CategoryListReqVO;
import com.yc.ship.module.resource.controller.admin.category.vo.CategoryRespVO;
import com.yc.ship.module.resource.controller.admin.resource.vo.ReducedResourceRespVO;
import com.yc.ship.module.resource.dal.dataobject.category.CategoryDO;
import com.yc.ship.module.resource.dal.dataobject.resource.ResourceDO;
import com.yc.ship.module.resource.dal.mysql.resource.ResourceMapper;
import com.yc.ship.module.resource.enums.UseStatusEnum;
import com.yc.ship.module.resource.service.category.CategoryService;
import com.yc.ship.module.trade.enums.SellMethodEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.framework.common.pojo.CommonResult.success;
import static com.yc.ship.module.product.enums.ErrorCodeConstants.*;
import static com.yc.ship.module.resource.enums.ErrorCodeConstants.BASE_NOT_EXISTS;
import static com.yc.ship.module.resource.enums.ErrorCodeConstants.PRODUCT_BASE_STOCK_NOT_ENOUGH;


/**
 * 产品基础信息 Service 实现类
 *
 * @author 管理员
 */
@Slf4j
@Service
@Validated
@RequiredArgsConstructor
public class ProductSpuServiceImpl implements ProductSpuService {

    private final RedissonClient redissonClient;
    private final ProductSkuMapper productSkuMapper;
    private final ProductSpuMapper productSpuMapper;
    private final ProductSaleChannelMapper productSaleChannelMapper;
    private final ProductBasicRuleMapper productBasicMapper;
    private final ProductSaleRuleMapper productSaleMapper;
    private final ProductTakeRuleMapper productTakeMapper;
    private final SpuShipMapper spuShipMapper;
    private final ProductCheckRuleMapper productCheckMapper;
    private final ProductRefundRuleMapper productRefundMapper;
    private final ProductNoticeRuleMapper productNoticeMapper;
    private final ProductOtherRuleMapper productOtherMapper;
    private final ProductGroupMapper productGroupMapper;
    private final ProductBaseMapper productBaseMapper;
    private final ResourceMapper resourceMapper;
    private final ProductGroupService productGroupService;
    private final CategoryService categoryService;


    @Override
    @Transactional
    public Long createProductSpu(ProductSpuSaveReqVO createReqVO) {
        if (createReqVO.getProductGroupList().isEmpty() && createReqVO.getPlatProductList().isEmpty()) {
            throw exception(PRODUCT_BASE_SPEC_NOT_EXISTS);
        }
        if (!createReqVO.getProductSkuList().isEmpty()) {
            BigDecimal minSalePrice = createReqVO.getProductSkuList().stream()
                    .min(Comparator.comparing(ProductSkuSaveReqVO::getSalePrice)).get().getSalePrice();
            createReqVO.setSalePrice(minSalePrice);
            createReqVO.setCostPrice(minSalePrice);
        }
        // 插入
        ProductSpuDO productSpu = BeanUtils.toBean(createReqVO, ProductSpuDO.class);
        productSpu.setId(IdWorker.getId(productSpu));
        productSpuMapper.insert(productSpu);

        String[] ships = createReqVO.getShipIds().split(",");
        for (String ship : ships) {
            SpuShipDO spuShip = new SpuShipDO();
            spuShip.setId(IdWorker.getId(spuShip));
            spuShip.setShipId(ship);
            spuShip.setProductId(productSpu.getId());
            spuShipMapper.insert(spuShip);
        }
        if (ObjectUtil.isNotEmpty(createReqVO.getProductSaleChannels())) {
            // 保存销售渠道
            String[] channels = createReqVO.getProductSaleChannels().split(",");
            for (String channel : channels) {
                ProductSaleChannelDO saleChannelDO = ProductSaleChannelDO.builder()
                        .productId(productSpu.getId())
                        .channelId(Integer.valueOf(channel))
                        .build();
                productSaleChannelMapper.insert(saleChannelDO);
            }
        }
        ProductBasicRuleDO basicRuleDO = BeanUtils.toBean(createReqVO.getProductBasicRule(), ProductBasicRuleDO.class);
        basicRuleDO.setId(productSpu.getId());
        productBasicMapper.insert(basicRuleDO);

        ProductSaleRuleDO saleRuleDO = BeanUtils.toBean(createReqVO.getProductSaleRule(), ProductSaleRuleDO.class);
        saleRuleDO.setId(productSpu.getId());
        productSaleMapper.insert(saleRuleDO);

        ProductTakeRuleDO takeRuleDO = BeanUtils.toBean(createReqVO.getProductTakeRule(), ProductTakeRuleDO.class);
        takeRuleDO.setId(productSpu.getId());
        productTakeMapper.insert(takeRuleDO);

        ProductCheckRuleDO checkRuleDO = BeanUtils.toBean(createReqVO.getProductCheckRule(), ProductCheckRuleDO.class);
        checkRuleDO.setId(productSpu.getId());
        productCheckMapper.insert(checkRuleDO);

        ProductRefundRuleDO refundRuleDO = BeanUtils.toBean(createReqVO.getProductRefundRule(), ProductRefundRuleDO.class);
        refundRuleDO.setId(productSpu.getId());
        productRefundMapper.insert(refundRuleDO);

        ProductNoticeRuleDO noticeRuleDO = BeanUtils.toBean(createReqVO.getProductNoticeRule(), ProductNoticeRuleDO.class);
        noticeRuleDO.setId(productSpu.getId());
        productNoticeMapper.insert(noticeRuleDO);

        ProductOtherRuleDO otherRuleDO = BeanUtils.toBean(createReqVO.getProductOtherRule(), ProductOtherRuleDO.class);
        otherRuleDO.setId(productSpu.getId());
        productOtherMapper.insert(otherRuleDO);


        List<PlatProductPriceRespVO> platProductPriceList = new ArrayList<>();
        if (createReqVO.getPlatProductList() != null && !createReqVO.getPlatProductList().isEmpty()) {
            Long tenantId = TenantContextHolder.getTenantId();
            createReqVO.getPlatProductList().forEach(group -> {
                platProductPriceList.addAll(group.getPlatProductPriceList());
                ProductGroupDO groupDO = BeanUtils.toBean(group, ProductGroupDO.class);
                groupDO.setId(IdWorker.getId(groupDO));
                groupDO.setProductId(productSpu.getId());
                Map<String, Object> idMap = productGroupMapper.selectDistributorProductId(tenantId, group.getPlatProductId());
                if (idMap.isEmpty()) {
                    throw exception(NO_PLAT_PRODUCT_AVAILABLE);
                }
                groupDO.setProductBaseId(MapUtil.getLong(idMap, "id"));
                productGroupMapper.insert(groupDO);
            });
        }
        // 保存sku 与 group 信息
        saveSkuAndGroupList(createReqVO.getProductGroupList(), createReqVO.getProductSkuList(),productSpu.getId());
        // 返回
        return productSpu.getId();
    }

    /**
     * 保存sku 与 group 信息
     * @param specGroupList 产品组成信息
     * @param productSkuList 产品规格信息
     * @param productId 产品id
     */
    void saveSkuAndGroupList(List<ProductGroupSaveReqVO> specGroupList,
                             List<ProductSkuSaveReqVO> productSkuList,
                             Long productId) {
        // 产品sku规格信息的新增与修改
        productGroupService.saveSkuAndGroupList(specGroupList, productSkuList, productId);
    }

    @Override
    @Transactional
    public void updateProductSpu(ProductSpuSaveReqVO updateReqVO) {
        if (updateReqVO.getProductGroupList().isEmpty() && updateReqVO.getPlatProductList().isEmpty()) {
            throw exception(PRODUCT_BASE_SPEC_NOT_EXISTS);
        }
        // 校验存在
        validateProductSpuExists(updateReqVO.getId());
        if (!updateReqVO.getProductSkuList().isEmpty()) {
            BigDecimal minSalePrice = updateReqVO.getProductSkuList().stream()
                    .min(Comparator.comparing(ProductSkuSaveReqVO::getSalePrice)).get().getSalePrice();
            updateReqVO.setSalePrice(minSalePrice);
            updateReqVO.setCostPrice(minSalePrice);
        }
        // 更新
        ProductSpuDO updateObj = BeanUtils.toBean(updateReqVO, ProductSpuDO.class);
        productSpuMapper.updateById(updateObj);

        if (ObjectUtil.isNotEmpty(updateReqVO.getProductSaleChannels())) {
            // 修改销售渠道
            productSaleChannelMapper.delete(ProductSaleChannelDO::getProductId, updateReqVO.getId());
            String[] channels = updateReqVO.getProductSaleChannels().split(",");
            for (String channel : channels) {
                ProductSaleChannelDO saleChannelDO = ProductSaleChannelDO.builder()
                        .productId(updateObj.getId())
                        .channelId(Integer.valueOf(channel))
                        .build();
                productSaleChannelMapper.insert(saleChannelDO);
            }
        }

        spuShipMapper.delete(SpuShipDO::getProductId, updateObj.getId());
        String[] ships = updateReqVO.getShipIds().split(",");
        for (String ship : ships) {
            SpuShipDO spuShip = new SpuShipDO();
            spuShip.setId(IdWorker.getId(spuShip));
            spuShip.setShipId(ship);
            spuShip.setProductId(updateReqVO.getId());
            spuShipMapper.insert(spuShip);
        }
        ProductBasicRuleDO basicRuleDO = BeanUtils.toBean(updateReqVO.getProductBasicRule(), ProductBasicRuleDO.class);
        productBasicMapper.updateById(basicRuleDO);

        ProductSaleRuleDO saleRuleDO = BeanUtils.toBean(updateReqVO.getProductSaleRule(), ProductSaleRuleDO.class);
        productSaleMapper.updateById(saleRuleDO);

        ProductTakeRuleDO takeRuleDO = BeanUtils.toBean(updateReqVO.getProductTakeRule(), ProductTakeRuleDO.class);
        productTakeMapper.updateById(takeRuleDO);

        ProductCheckRuleDO checkRuleDO = BeanUtils.toBean(updateReqVO.getProductCheckRule(), ProductCheckRuleDO.class);
        productCheckMapper.updateById(checkRuleDO);

        ProductRefundRuleDO refundRuleDO = BeanUtils.toBean(updateReqVO.getProductRefundRule(), ProductRefundRuleDO.class);
        productRefundMapper.updateById(refundRuleDO);

        ProductNoticeRuleDO noticeRuleDO = BeanUtils.toBean(updateReqVO.getProductNoticeRule(), ProductNoticeRuleDO.class);
        productNoticeMapper.updateById(noticeRuleDO);

        ProductOtherRuleDO otherRuleDO = BeanUtils.toBean(updateReqVO.getProductOtherRule(), ProductOtherRuleDO.class);
        productOtherMapper.updateById(otherRuleDO);

        // 保存sku信息
        saveSkuAndGroupList(updateReqVO.getProductGroupList(), updateReqVO.getProductSkuList(), updateReqVO.getId());
    }

    @Override
    @Transactional
    public void deleteProductSpu(Long id) {
        // 校验存在
        validateProductSpuExists(id);
        // 删除
        productSpuMapper.deleteById(id);
        productBasicMapper.deleteById(id);
        productSaleMapper.deleteById(id);
        productTakeMapper.deleteById(id);
        productCheckMapper.deleteById(id);
        productRefundMapper.deleteById(id);
        productNoticeMapper.deleteById(id);
        productOtherMapper.deleteById(id);
        productGroupMapper.delete(ProductGroupDO::getProductId, id);
        productSaleChannelMapper.delete(ProductSaleChannelDO::getProductId, id);
    }

    private void validateProductSpuExists(Long id) {
        if (productSpuMapper.selectById(id) == null) {
            throw exception(PRODUCT_SPU_NOT_EXISTS);
        }
    }

    @Override
    public ProductSpuDO getProductSpu(Long id) {
        return productSpuMapper.selectById(id);
    }

    @Override
    public ProductSpuRespVO getProductSpuResp(Long id, String date, Long planId, boolean isEdit) {
        ProductSpuDO productSpuDO = productSpuMapper.selectOneWithoutTenant(id);
        ProductSpuRespVO spuRespVO = BeanUtils.toBean(productSpuDO, ProductSpuRespVO.class);

        if (productSpuDO == null) {
            return null;
        }
        Long agencyId;
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if (loginUser != null) {
            Map<String, Object> map = productGroupMapper.queryAgencyId(loginUser.getId(), loginUser.getTenantId());
            agencyId = MapUtil.getLong(map, "distributorId", null);
        } else {
            agencyId = null;
        }

        TenantUtils.execute(productSpuDO.getTenantId(), () -> {
            List<ProductSaleChannelDO> channelList = productSaleChannelMapper.selectList(ProductSaleChannelDO::getProductId, id);
            StringBuilder saleChannels = new StringBuilder();
            for (ProductSaleChannelDO channel : channelList) {
                saleChannels.append(channel.getChannelId()).append(",");
            }
            spuRespVO.setProductSaleChannels(saleChannels.substring(0, saleChannels.length() - 1));

            ProductBasicRuleDO basicRuleDO = productBasicMapper.selectById(id);
            spuRespVO.setProductBasicRule(BeanUtils.toBean(basicRuleDO, ProductBasicRuleRespVO.class));

            List<SpuShipDO> spuShipList = spuShipMapper.selectList(
                    new LambdaQueryWrapperX<SpuShipDO>()
                    .eqIfPresent(SpuShipDO::getProductId, id)
                    .eq(SpuShipDO::getDeleted, false)
            );
            String shipIds = spuShipList.stream().map(SpuShipDO::getShipId).collect(Collectors.joining(","));
            spuRespVO.setShipIds(shipIds);

            ProductSaleRuleDO saleRuleDO = productSaleMapper.selectById(id);
            spuRespVO.setProductSaleRule(BeanUtils.toBean(saleRuleDO, ProductSaleRuleRespVO.class));

            ProductTakeRuleDO takeRuleDO = productTakeMapper.selectById(id);
            spuRespVO.setProductTakeRule(BeanUtils.toBean(takeRuleDO, ProductTakeRuleRespVO.class));

            ProductCheckRuleDO checkRuleDO = productCheckMapper.selectById(id);
            spuRespVO.setProductCheckRule(BeanUtils.toBean(checkRuleDO, ProductCheckRuleRespVO.class));

            ProductRefundRuleDO refundRuleDO = productRefundMapper.selectById(id);
            spuRespVO.setProductRefundRule(BeanUtils.toBean(refundRuleDO, ProductRefundRuleRespVO.class));

            ProductNoticeRuleDO noticeRuleDO = productNoticeMapper.selectById(id);
            spuRespVO.setProductNoticeRule(BeanUtils.toBean(noticeRuleDO, ProductNoticeRuleRespVO.class));

            ProductOtherRuleDO otherRuleDO = productOtherMapper.selectById(id);
            spuRespVO.setProductOtherRule(BeanUtils.toBean(otherRuleDO, ProductOtherRuleRespVO.class));

            List<ProductGroupRespVO> productGroupList = productGroupMapper.selectSpuGroupByPlanIdList(id,null);
            spuRespVO.setOwnThisPlan(false);
            List<ProductSkuDO> skuDOList = productSkuMapper.selectList(ProductSkuDO::getProductId, id);
            List<ProductSkuRespVO> skuList = BeanUtils.toBean(skuDOList, ProductSkuRespVO.class);

            List<PlatProductRespVO> platProductList = productGroupMapper.selectPlatProductList(id);
            spuRespVO.setProductGroupList(productGroupList);
            spuRespVO.setProductSkuList(skuList);
            spuRespVO.setPlatProductList(platProductList);

        });

        return spuRespVO;
    }

    @Override
    public ProductSpuRespVO getProductSpuResp(Long id, String date, Long planId) {
        return getProductSpuResp(id,date,planId,false);
    }


    @Override
    public PageResult<ProductSpuRespVO> getProductSpuPage(ProductSpuPageReqVO pageReqVO) {
        IPage<ProductSpuRespVO> iPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<ProductSpuRespVO> page = productSpuMapper.selectPage2(iPage, pageReqVO);
        for (ProductSpuRespVO item : page.getRecords()) {
            List<ProductSaleChannelDO> channelList = productSaleChannelMapper.selectList(ProductSaleChannelDO::getProductId, item.getId());
            StringBuilder saleChannels = new StringBuilder();
            for (ProductSaleChannelDO channel : channelList) {
                saleChannels.append(channel.getChannelId()).append(",");
            }
            item.setProductSaleChannels(saleChannels.substring(0, saleChannels.length() - 1));
            List<CategoryRespVO> list = categoryService.getCategoryRespListByIds(item.getCategoryId());
            String newName = list.stream().map(CategoryRespVO::getCateName).collect(Collectors.joining("/"));
            item.setCategoryName(newName);
        }
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public PageResult<ProductSpuRespVO> getAppletProductPage(ProductSpuPageReqVO pageReqVO) {
        IPage<ProductSpuRespVO> iPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<ProductSpuRespVO> page = productSpuMapper.selectAppletPage(iPage, pageReqVO);
        page.getRecords().forEach(product -> {
            product.setProductGroupList(productGroupMapper.selectSpuGroupList(product.getId(),null));
            ProductBasicRuleDO basicRuleDO = productBasicMapper.selectById(product.getId());
            product.setProductBasicRule(BeanUtils.toBean(basicRuleDO, ProductBasicRuleRespVO.class));
        });
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public CommonResult<List<ProductSpuRespDTO>> getProductListByTenantId(Long tenantId) {
        List<ProductSpuDO> list = productSpuMapper.selectList(ProductSpuDO::getTenantId, tenantId, ProductSpuDO::getIsUse, 1);
        return success(BeanUtils.toBean(list, ProductSpuRespDTO.class));
    }

    @Override
    public List<ProductSpuRespDTO> listAllSpu() {
        List<ProductSpuSimpleVO> list = productSpuMapper.listAllSpu();
        return BeanUtils.toBean(list, ProductSpuRespDTO.class);
    }

    @Override
    public List<ProductSpuDO> getProductList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return productSpuMapper.selectBatchIds(ids);
    }


    @Override
    @TenantIgnore
    public PageResult<ProductSpuRespVO> selectSpuListByTenantId(ProductSpuPageReqVO pageReqVO) {

        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        Map<String, Object> map = productGroupMapper.queryAgencyId(loginUser.getId(), loginUser.getTenantId());
        Long agencyId = MapUtil.getLong(map, "distributorId", null);

        IPage<ProductSpuRespVO> iPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<ProductSpuRespVO> page = productSpuMapper.selectPlatSpuList(iPage, pageReqVO);
        page.getRecords().forEach(spu -> {
            spu.setProductGroupList(productGroupMapper.selectSpuGroupListV2(spu.getId()));
            ProductBasicRuleDO basicRuleDO = productBasicMapper.selectById(spu.getId());
            spu.setProductBasicRule(BeanUtils.toBean(basicRuleDO, ProductBasicRuleRespVO.class));
            if (agencyId != null) {
                // 查询平台设置分销产品价格
                spu.setPlatProductPriceList(productGroupMapper.selectPlatProductPriceList(agencyId, spu.getId()));
            }
            List<CategoryRespVO> list = categoryService.getCategoryRespListByIds(spu.getCategoryId());
            String newName = list.stream().map(CategoryRespVO::getCateName).collect(Collectors.joining("/"));
            spu.setCategoryName(newName);
        });
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public void updateStatus(Long id, Integer status) {
        productSpuMapper.update(new LambdaUpdateWrapper<ProductSpuDO>().eq(ProductSpuDO::getId, id)
                .set(ProductSpuDO::getIsUse, status));

        //上下架修改分销产品状态
        productGroupMapper.updateDistributorProductIsUse(id,status);

    }

    @Override
    public List<ProductSpuDO> getProductSpuListByStatus( Long categoryId,Integer channelId, Integer status) {
        return productSpuMapper.getProductSpuListByStatus(categoryId,channelId,status);
    }

    @Override
    public List<ReducedResourceRespVO> reduceProductStock(List<ProductReduceStockReqVO> list) {

        List<ReducedResourceRespVO> resultList = new ArrayList<>();
        for (ProductReduceStockReqVO reqVO : list) {
            if(!reqVO.getBaseReduceList().isEmpty()) {
                ProductBasicRuleDO basicRuleDO = reduceProductStockPreVerify(reqVO);
                for (ProductReduceStockReqVO baseVO : reqVO.getBaseReduceList()) {
                    ProductBaseDO productBaseDO = productBaseMapper.selectOne(ProductBaseDO::getId, baseVO.getId());
                    if (productBaseDO == null) {
                        throw exception(BASE_NOT_EXISTS);
                    }
                    Assert.isTrue(productBaseDO.getStock() == null || productBaseDO.getStock() >= baseVO.getNum(),
                            () -> exception(PRODUCT_BASE_STOCK_NOT_ENOUGH.getCode(),"基础产品：" + productBaseDO.getName()+"库存不足："+PRODUCT_BASE_STOCK_NOT_ENOUGH.getCode()));

                    // 扣减资源库存
                    List<ReducedResourceRespVO> resourceDOList = changeResourceStock(baseVO);
                    resourceDOList.forEach(r -> {
                        r.setProductBaseId(baseVO.getId());
                        r.setProductBaseName(productBaseDO.getName());
                        r.setProductId(basicRuleDO.getId());
                        r.setProductName(basicRuleDO.getProductName());
                    });
                    resultList.addAll(resourceDOList);

                    // 扣减基础产品库存
                    if (productBaseDO.getStock() != null) {
                        String lockKey = String.format(REDUCE_BASE_PRODUCT_LOCK, productBaseDO.getId());
                        RLock lock = redissonClient.getLock(lockKey);
                        try {
                            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                                productBaseDO.setStock(productBaseDO.getStock() - baseVO.getNum());
                                productBaseMapper.updateById(productBaseDO);
                            } else {
                                log.error("扣减基础产品库存失败，未获取到锁。productBaseId:{}", productBaseDO.getId());
                                throw exception(REDUCE_BASE_PRODUCT_FAIL_NO_LOCK, productBaseDO.getId());
                            }

                        } catch (Exception e) {
                            log.error("扣减基础产品库存异常 productBaseId:{}", productBaseDO.getId(), e);
                            throw exception(REDUCE_BASE_PRODUCT_EXCEPTION.getCode(), productBaseDO.getId()+"库存不足"+REDUCE_BASE_PRODUCT_EXCEPTION.getCode());
                        } finally {
                            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    }
                }
                // 扣减产品库存
                if (basicRuleDO.getStock() != null) {
                    String lockKey = String.format(REDUCE_PRODUCT_LOCK, basicRuleDO.getId());
                    RLock lock = redissonClient.getLock(lockKey);
                    try {
                        if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                            basicRuleDO.setStock(basicRuleDO.getStock() - reqVO.getNum());
                            productBasicMapper.updateById(basicRuleDO);
                        } else {
                            log.error("扣减产品库存失败，未获取到锁。productId:{}", basicRuleDO.getId());
                            throw exception(REDUCE_PRODUCT_FAIL_NO_LOCK, basicRuleDO.getId());
                        }

                    } catch (Exception e) {
                        log.error("扣减产品库存异常 productId:{}", basicRuleDO.getId(), e);
                        throw exception(REDUCE_PRODUCT_EXCEPTION.getCode(), basicRuleDO.getId()+"库存不足"+REDUCE_PRODUCT_EXCEPTION.getCode());
                    } finally {
                        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                            lock.unlock();
                        }
                    }
                }
            }
        }
        return resultList;
    }

    /**
     * 扣减产品数量校验
     *
     * @param reqVO 参数
     * @return 组合产品基础信息
     */
    private ProductBasicRuleDO reduceProductStockPreVerify(ProductReduceStockReqVO reqVO) {

        ProductSpuDO productSpuDO = productSpuMapper.selectOne(ProductSpuDO::getId, reqVO.getId());
        if (productSpuDO == null) {
            throw exception(PRODUCT_SPU_NOT_EXISTS);
        }

        Assert.isTrue(UseStatusEnum.isEnable(productSpuDO.getIsUse()), () -> exception(PRODUCT_DISABLE));

        ProductBasicRuleDO basicRuleDO = productBasicMapper.selectOne(ProductBasicRuleDO::getId, reqVO.getId());
        if (basicRuleDO == null) {
            throw exception(BASIC_RULE_NOT_EXISTS);
        }

        Assert.isTrue(basicRuleDO.getStock() == null || basicRuleDO.getStock() > reqVO.getNum(),
                () -> exception(PRODUCT_STOCK_NOT_ENOUGH.getCode(),"库存不足"+PRODUCT_STOCK_NOT_ENOUGH.getCode()));

        Assert.isTrue(!reqVO.getBaseReduceList().isEmpty(), () -> exception(PRODUCT_BASE_REDUCE_INFO_NOT_EXISTS));

        basicRuleDO.setProductName(productSpuDO.getProductName());
        return basicRuleDO;
    }

    /**
     * 扣减资源库存
     *
     * @param changeVO 库存变更信息
     */
    private List<ReducedResourceRespVO> changeResourceStock(ProductReduceStockReqVO changeVO) {
        int toReduceNum = changeVO.getNum(); // 待扣减数量
        Long resourceId = null;              // 已扣减资源id
        List<ReducedResourceRespVO> reducedResourceList = new ArrayList<>();
        String lockKey = String.format(REDUCE_RESOURCE_LOCK, changeVO.getId());
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                ResourceDO resourceDO;
                if (changeVO.getProductResourceId() != null) {
                    // 定制游传资源id
                    resourceDO = resourceMapper.selectById(changeVO.getProductResourceId());
                } else {
                    resourceDO = resourceMapper.getByProductBaseId(changeVO.getId());
                }
                if (resourceDO != null) {
                    // 扣减优先资源库存
                    if (resourceDO.getStock() != null) {
                        if (resourceDO.getStock() > toReduceNum) {
                            resourceDO.setStock(resourceDO.getStock() - toReduceNum);
                            resourceMapper.updateById(resourceDO);
                            ReducedResourceRespVO vo = BeanUtils.toBean(resourceDO, ReducedResourceRespVO.class);
                            vo.setReducedNum(toReduceNum);
                            reducedResourceList.add(vo);
                        } else {
                            // 优先资源库存不足 记录优先资源id
                            resourceId = resourceDO.getId();
                        }
                    } else {
                        ReducedResourceRespVO vo = BeanUtils.toBean(resourceDO, ReducedResourceRespVO.class);
                        vo.setReducedNum(toReduceNum);
                        reducedResourceList.add(vo);
                    }
                }
                // 优先资源库存不足
                if (resourceId != null) {
                    List<ResourceDO> resourceList = resourceMapper.getListWithoutExcludeId(changeVO.getId(), resourceId);
                    boolean hasReduced = false;
                    for (ResourceDO resource : resourceList) {
                        // 循环扣减同类其他资源库存
                        if (resource.getStock() != null) {
                            if (resourceDO.getStock() > toReduceNum) {
                                resourceDO.setStock(resourceDO.getStock() - toReduceNum);
                                resourceMapper.updateById(resourceDO);
                                ReducedResourceRespVO vo = BeanUtils.toBean(resourceDO, ReducedResourceRespVO.class);
                                vo.setReducedNum(toReduceNum);
                                reducedResourceList.add(vo);
                                hasReduced = true;
                                break;
                            }
                        } else {
                            ReducedResourceRespVO vo = BeanUtils.toBean(resource, ReducedResourceRespVO.class);
                            vo.setReducedNum(toReduceNum);
                            reducedResourceList.add(vo);
                            hasReduced = true;
                            break;
                        }
                    }
                    // 资源不足，抛出异常
                    Assert.isTrue(!hasReduced, () -> exception(RESOURCE_STOCK_NOT_ENOUGH.getCode(),"库存不足"+RESOURCE_STOCK_NOT_ENOUGH.getCode()));
                }
            } else {
                log.error("扣减资源库存失败，未获取到锁。resourceId:{}", changeVO.getId());
                throw exception(REDUCE_RESOURCE_FAIL_NO_LOCK, changeVO.getId());
            }

        } catch (Exception e) {
            log.error("扣减资源库存异常 resourceId:{}", changeVO.getId(), e);
            throw exception(REDUCE_RESOURCE_EXCEPTION.getCode(), changeVO.getId()+"库存不足"+REDUCE_RESOURCE_EXCEPTION.getCode());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        return reducedResourceList;
    }

    @Override
    public List<Map<String,Object>> getProductSpuList(Collection<Long> categoryIds) {
        return productSpuMapper.getProductSpuList(categoryIds);
    }

    @Override
    public List<TreeNode> getCategoryAndSpuList() {
        CategoryListReqVO reqVO = new CategoryListReqVO();
        reqVO.setType(1);
        reqVO.setUseStatus(UseStatusEnum.ENABLE.getStatus());
        List<TreeNode> treeList = categoryService.getCategoryTreeList(reqVO);
        List<TreeNode>  resultList = new ArrayList<>();
        resultList.addAll(treeList);
        treeList.forEach(treeNode -> {
            List<ProductSpuDO> productSpuList = productSpuMapper.selectListByCategory(Long.parseLong(treeNode.getId().toString()));
            if (CollUtil.isNotEmpty(productSpuList)){
                List<TreeNode> productTreeList = productSpuList.stream().map(e -> new TreeNode<>(e.getId(), e.getCategoryId(), e.getProductName(), e.getSortNum())).collect(Collectors.toList());
                resultList.addAll(productTreeList);
            }
        });
        return resultList;
    }

    @Override
    public List<TreeNode> getDistributorProductSpuList() {
        CategoryListReqVO reqVO = new CategoryListReqVO();
        reqVO.setType(1);
        reqVO.setUseStatus(UseStatusEnum.ENABLE.getStatus());
        List<TreeNode> treeList = categoryService.getCategoryTreeList(reqVO);
        List<TreeNode>  resultList = new ArrayList<>();
        resultList.addAll(treeList);
        treeList.forEach(treeNode -> {
            MPJLambdaWrapper<ProductSpuDO> wrapper = new MPJLambdaWrapperX<ProductSpuDO>()
                    .selectAll(ProductSpuDO.class)
                    .innerJoin(ProductSaleChannelDO.class, ProductSaleChannelDO::getProductId, ProductSpuDO::getId)
                    .in(ProductSaleChannelDO::getChannelId, SellMethodEnum.OTA.getType(), SellMethodEnum.OTC.getType())
                    .eq(ProductSpuDO::getIsUse,UseStatusEnum.ENABLE.getStatus())
                    .eq(ProductSpuDO::getCategoryId,Long.parseLong(treeNode.getId().toString()))
                    .groupBy(ProductSpuDO::getId);
            List<ProductSpuDO> productSpuList =productSpuMapper.selectJoinList(ProductSpuDO.class, wrapper);
            if (CollUtil.isNotEmpty(productSpuList)){
                List<TreeNode> productTreeList = productSpuList.stream().map(e -> new TreeNode<>(e.getId(), e.getCategoryId(), e.getProductName(), e.getSortNum())).collect(Collectors.toList());
                resultList.addAll(productTreeList);
            }
        });
        return resultList;
    }

    @Override
    public List<ProductSpuSimpleVO> selectSimpleList(ProductSpuPageReqVO pageReqVO) {
        if (pageReqVO.getIsAdmin() != null && pageReqVO.getIsAdmin() == 1) {
            return productSpuMapper.selectSimpleList(pageReqVO);
        } else {
            //获取登录旅行社
            return  productSpuMapper.selectSimpleList(pageReqVO);
        }
    }

    @Override
    public List<ProductSpuSimpleVO> listByShipId(Long shipId) {
            //获取游船绑定的附加产品
        return  productSpuMapper.listByShipId(shipId);
    }

    @Override
    public List<ProductSkuDO> getProductSkuList(List<Long> ids) {
        return productSkuMapper.selectList(new LambdaQueryWrapper<ProductSkuDO>()
                .in(ProductSkuDO::getProductId, ids)
                .eq(ProductSkuDO::getDeleted, 0)
        );
    }

    @Override
    public List<ProductSpuSimpleRespVO> getProductSpuListByCategory(Long categoryId) {
        List<ProductSpuDO> dataList = productSpuMapper.selectProductSpuListByCategory(categoryId);
        return BeanUtils.toBean(dataList, ProductSpuSimpleRespVO.class);
    }

}
