package com.czg.service.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.config.RabbitPublisher;
import com.czg.enums.YesNoEnum;
import com.czg.product.dto.ProductStockSubtractDTO;
import com.czg.product.entity.*;
import com.czg.product.enums.InOutItemEnum;
import com.czg.product.enums.InOutTypeEnum;
import com.czg.product.service.ConsStockFlowService;
import com.czg.product.service.ProductRpcService;
import com.czg.product.service.ProductStockFlowService;
import com.czg.product.vo.ProductVO;
import com.czg.service.RedisService;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ProdConsRelationMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;

import static com.czg.constant.CacheConstant.ADMIN_CLIENT_PRODUCT_LIST;
import static com.czg.constant.CacheConstant.SHOP_PRODUCT_STOCK;

/**
 * 商品RPC远程调用服务接口实现
 *
 * @author tankaikai
 * @since 2025-03-01 10:19
 */
@Slf4j
@DubboService
public class ProductRpcServiceImpl implements ProductRpcService {

    @Resource
    private ProductMapper productMapper;

    @Resource
    private ProdConsRelationMapper prodConsRelationMapper;

    @Resource
    private ConsInfoMapper consInfoMapper;

    @Resource
    private ConsStockFlowService consStockFlowService;
    @Resource
    private ProductStockFlowService productStockFlowService;
    @Resource
    private RabbitPublisher rabbitPublisher;
    @Resource
    private RedisService redisService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    //@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#shopId", allEntries = true, beforeInvocation = true)
    public void paySuccessSubtractStock(Long shopId, Long orderId, List<Map<String, Object>> dataList) {
        List<ProductStockSubtractDTO> list = BeanUtil.copyToList(dataList, ProductStockSubtractDTO.class);
        if (CollUtil.isEmpty(list)) {
            return;
        }
        boolean isLowWarnLine = false;
        for (ProductStockSubtractDTO dto : list) {
            Product product = productMapper.selectOneById(dto.getProductId());
            if (product == null) {
                continue;
            }
            // 商品未开启库存
            if (product.getIsStock() == YesNoEnum.NO.value()) {
                continue;
            }
            productMapper.updateProductStockNum(dto.getProductId(), dto.getShopId(), "sub", dto.getNum());
            // 记录商品库存流水
            ProductStockFlow flow = new ProductStockFlow();
            flow.setCreateUserId(1L);
            flow.setCreateUserName("银收客");
            flow.setShopId(shopId);
            flow.setProductId(product.getId());
            flow.setProductName(product.getName());
            flow.setBeforeNumber(NumberUtil.toBigDecimal(product.getStockNumber()));
            flow.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, NumberUtil.toBigDecimal(dto.getNum())));
            flow.setAfterNumber(NumberUtil.sub(NumberUtil.toBigDecimal(product.getStockNumber()), NumberUtil.toBigDecimal(dto.getNum())));
            flow.setInOutType(InOutTypeEnum.OUT.value());
            flow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
            flow.setOrderId(orderId);
            productStockFlowService.saveFlow(flow);
            cleanCategoryProduct(shopId, product.getCategoryId());
            refreshRedisProdStock(shopId, product.getId(), flow.getAfterNumber());
            Integer warnLine = ObjUtil.defaultIfNull(product.getWarnLine(), 10);
            if (!isLowWarnLine && NumberUtil.isLess(flow.getAfterNumber(), Convert.toBigDecimal(warnLine))) {
                isLowWarnLine = true;
            }
            // 查询商品绑定耗材信息
            List<ProdConsRelation> relationList = prodConsRelationMapper.selectListByQuery(QueryWrapper.create().eq(ProdConsRelation::getProductId, dto.getProductId()));
            if (CollUtil.isEmpty(relationList)) {
                continue;
            }
            for (ProdConsRelation prodConsRelation : relationList) {
                // 耗材id
                Long consInfoId = prodConsRelation.getConsInfoId();
                // 耗材消耗数量
                BigDecimal surplusStock = prodConsRelation.getSurplusStock();
                if (surplusStock == null) {
                    continue;
                }
                // 实际消耗数量 = 耗材消耗数量 * 商品购买数量
                surplusStock = NumberUtil.mul(surplusStock, dto.getNum());
                ConsInfo consInfo = consInfoMapper.selectOneById(consInfoId);
                if (consInfo == null) {
                    continue;
                }
                BigDecimal stockNumber = consInfo.getStockNumber();
                consInfo.setStockNumber(NumberUtil.sub(stockNumber, surplusStock));
                // 更新耗材库存数量
                consInfoMapper.update(consInfo);
                // 插入耗材流水记录
                ConsStockFlow consStockFlow = new ConsStockFlow();
                consStockFlow.setShopId(shopId);
                consStockFlow.setVendorId(null);
                consStockFlow.setInOutType(InOutTypeEnum.OUT.value());
                consStockFlow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
                consStockFlow.setInOutDate(LocalDate.now());
                consStockFlow.setConId(consInfo.getId());
                consStockFlow.setConName(consInfo.getConName());
                consStockFlow.setUnitName(consInfo.getConUnit());
                consStockFlow.setBeforeNumber(stockNumber);
                consStockFlow.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, surplusStock));
                consStockFlow.setAfterNumber(consInfo.getStockNumber());
                consStockFlow.setSubTotal(NumberUtil.mul(surplusStock, consInfo.getPrice()));
                consStockFlow.setProductId(dto.getProductId());
                //consStockFlow.setSkuId(0L);
                consStockFlow.setOrderId(orderId);
                consStockFlowService.saveFlow(consStockFlow);
            }
        }
        if (isLowWarnLine) {
            ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId)));
        }
        log.info("ProductService.--------------------------------------------库存更新成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    //@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#shopId", allEntries = true, beforeInvocation = true)
    public void orderCancelRecoverStock(Long shopId, Long orderId, List<Map<String, Object>> dataList) {
        List<ProductStockSubtractDTO> list = BeanUtil.copyToList(dataList, ProductStockSubtractDTO.class);
        if (CollUtil.isEmpty(list)) {
            return;
        }
        boolean isLowWarnLine = false;
        for (ProductStockSubtractDTO dto : list) {
            Product product = productMapper.selectOneById(dto.getProductId());
            productMapper.updateProductStockNum(dto.getProductId(), dto.getShopId(), "add", dto.getNum());
            // 记录商品库存流水
            ProductStockFlow flow = new ProductStockFlow();
            flow.setCreateUserId(1L);
            flow.setCreateUserName("银收客");
            flow.setShopId(shopId);
            flow.setProductId(product.getId());
            flow.setProductName(product.getName());
            flow.setBeforeNumber(NumberUtil.toBigDecimal(product.getStockNumber()));
            flow.setInOutNumber(NumberUtil.toBigDecimal(dto.getNum()));
            flow.setAfterNumber(NumberUtil.add(NumberUtil.toBigDecimal(product.getStockNumber()), NumberUtil.toBigDecimal(dto.getNum())));
            flow.setInOutType(InOutTypeEnum.OUT.value());
            flow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
            flow.setRemark("红冲订单取消/退菜/退单消耗的库存");
            flow.setOrderId(orderId);
            productStockFlowService.saveFlow(flow);
            refreshRedisProdStock(shopId, product.getId(), flow.getAfterNumber());
            Integer warnLine = ObjUtil.defaultIfNull(product.getWarnLine(), 10);
            if (!isLowWarnLine && (NumberUtil.isLessOrEqual(flow.getBeforeNumber(), BigDecimal.ZERO) || NumberUtil.isLess(flow.getAfterNumber(), Convert.toBigDecimal(warnLine)))) {
                isLowWarnLine = true;
            }
            // 查询商品绑定耗材信息
            List<ProdConsRelation> relationList = prodConsRelationMapper.selectListByQuery(QueryWrapper.create().eq(ProdConsRelation::getProductId, dto.getProductId()));
            if (CollUtil.isEmpty(relationList)) {
                continue;
            }
            for (ProdConsRelation prodConsRelation : relationList) {
                // 耗材id
                Long consInfoId = prodConsRelation.getConsInfoId();
                // 耗材消耗数量
                BigDecimal surplusStock = prodConsRelation.getSurplusStock();
                if (surplusStock == null) {
                    continue;
                }
                // 实际消耗数量 = 耗材消耗数量 * 商品购买数量
                surplusStock = NumberUtil.mul(surplusStock, dto.getNum());
                ConsInfo consInfo = consInfoMapper.selectOneById(consInfoId);
                if (consInfo == null) {
                    continue;
                }
                BigDecimal stockNumber = consInfo.getStockNumber();
                consInfo.setStockNumber(NumberUtil.add(stockNumber, surplusStock));
                // 更新耗材库存数量
                consInfoMapper.update(consInfo);
                // 插入耗材流水记录
                ConsStockFlow consStockFlow = new ConsStockFlow();
                consStockFlow.setShopId(shopId);
                consStockFlow.setInOutType(InOutTypeEnum.OUT.value());
                consStockFlow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
                consStockFlow.setInOutDate(LocalDate.now());
                consStockFlow.setConId(consInfo.getId());
                consStockFlow.setConName(consInfo.getConName());
                consStockFlow.setUnitName(consInfo.getConUnit());
                consStockFlow.setBeforeNumber(stockNumber);
                consStockFlow.setInOutNumber(surplusStock);
                consStockFlow.setAfterNumber(consInfo.getStockNumber());
                consStockFlow.setSubTotal(NumberUtil.mul(surplusStock, consInfo.getPrice()));
                consStockFlow.setProductId(dto.getProductId());
                //consStockFlow.setSkuId(0L);
                consStockFlow.setRemark("红冲订单取消/退菜/退单消耗的库存");
                consStockFlow.setOrderId(orderId);
                consStockFlowService.saveFlow(consStockFlow);
            }
        }
        if (isLowWarnLine) {
            ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId)));
        }
        log.info("ProductService.--------------------------------------------库存更新成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderRefundReturnStock(Long shopId, Long orderId, List<Map<String, Object>> dataList) {
        List<ProductStockSubtractDTO> list = BeanUtil.copyToList(dataList, ProductStockSubtractDTO.class);
        if (CollUtil.isEmpty(list)) {
            return;
        }
        log.info(">>>>>>>>>>>>>>>>>：入参1：{}", list.size());
        boolean isLowWarnLine = false;
        for (ProductStockSubtractDTO dto : list) {
            Product product = productMapper.selectOneById(dto.getProductId());
            log.info(">>>>>>>>>>>>>>>>>：入参2：{}", product.getName());
            // 商品是否允许退款退货时归还库存
            if (product.getIsRefundStock() == YesNoEnum.NO.value()) {
                continue;
            }
            // 商品未开启库存
            if (product.getIsStock() == YesNoEnum.NO.value()) {
                continue;
            }
            log.info(">>>>>>>>>>>>>>>>>：入参3：{}", product.getName());
            productMapper.updateProductStockNum(dto.getProductId(), dto.getShopId(), "add", dto.getNum());
            // 记录商品库存流水
            ProductStockFlow flow = new ProductStockFlow();
            flow.setCreateUserId(1L);
            flow.setCreateUserName("银收客");
            flow.setShopId(shopId);
            flow.setProductId(product.getId());
            flow.setProductName(product.getName());
            flow.setBeforeNumber(NumberUtil.toBigDecimal(product.getStockNumber()));
            flow.setInOutNumber(NumberUtil.toBigDecimal(dto.getNum()));
            flow.setAfterNumber(NumberUtil.add(NumberUtil.toBigDecimal(product.getStockNumber()), NumberUtil.toBigDecimal(dto.getNum())));
            flow.setInOutType(InOutTypeEnum.OUT.value());
            flow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
            flow.setRemark("红冲订单取消/退菜/退单消耗的库存");
            flow.setOrderId(orderId);
            productStockFlowService.saveFlow(flow);
            String key = StrUtil.format(SHOP_PRODUCT_STOCK, shopId, product.getId());
            log.info(">>>>>>>>>>>>>>>>>：入参4：{}", redisService.get(key));
            refreshRedisProdStock(shopId, product.getId(), flow.getAfterNumber());
            log.info(">>>>>>>>>>>>>>>>>：入参5：{}", redisService.get(key));
            Integer warnLine = ObjUtil.defaultIfNull(product.getWarnLine(), 10);
            if (!isLowWarnLine && (NumberUtil.isLessOrEqual(flow.getBeforeNumber(), BigDecimal.ZERO) || NumberUtil.isLess(flow.getAfterNumber(), Convert.toBigDecimal(warnLine)))) {
                isLowWarnLine = true;
            }
            // 查询商品绑定耗材信息
            List<ProdConsRelation> relationList = prodConsRelationMapper.selectListByQuery(QueryWrapper.create().eq(ProdConsRelation::getProductId, dto.getProductId()));
            if (CollUtil.isEmpty(relationList)) {
                continue;
            }
            for (ProdConsRelation prodConsRelation : relationList) {
                // 耗材id
                Long consInfoId = prodConsRelation.getConsInfoId();
                // 耗材消耗数量
                BigDecimal surplusStock = prodConsRelation.getSurplusStock();
                if (surplusStock == null) {
                    continue;
                }
                // 实际消耗数量 = 耗材消耗数量 * 商品购买数量
                surplusStock = NumberUtil.mul(surplusStock, dto.getNum());
                ConsInfo consInfo = consInfoMapper.selectOneById(consInfoId);
                if (consInfo == null) {
                    continue;
                }
                BigDecimal stockNumber = consInfo.getStockNumber();
                consInfo.setStockNumber(NumberUtil.add(stockNumber, surplusStock));
                // 更新耗材库存数量
                consInfoMapper.update(consInfo);
                // 插入耗材流水记录
                ConsStockFlow consStockFlow = new ConsStockFlow();
                consStockFlow.setShopId(shopId);
                consStockFlow.setInOutType(InOutTypeEnum.OUT.value());
                consStockFlow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
                consStockFlow.setInOutDate(LocalDate.now());
                consStockFlow.setConId(consInfo.getId());
                consStockFlow.setConName(consInfo.getConName());
                consStockFlow.setUnitName(consInfo.getConUnit());
                consStockFlow.setBeforeNumber(stockNumber);
                consStockFlow.setInOutNumber(surplusStock);
                consStockFlow.setAfterNumber(consInfo.getStockNumber());
                consStockFlow.setSubTotal(NumberUtil.mul(surplusStock, consInfo.getPrice()));
                consStockFlow.setProductId(dto.getProductId());
                // consStockFlow.setSkuId(0L);
                consStockFlow.setOrderId(orderId);
                consStockFlow.setRemark("红冲订单取消/退菜/退单消耗的库存");
                consStockFlowService.saveFlow(consStockFlow);
            }
        }
        if (isLowWarnLine) {
            ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId)));
        }
        log.info("ProductService.--------------------------------------------库存更新成功");
    }

    @Override
    public List<ProductVO> listAndLowPrice(Long shopId, List<Long> productIds) {
        return productMapper.productList(shopId, productIds);
    }

    @Override
    public void cleanCategoryProduct(Long shopId, Long categoryId) {
        String key = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId + "::" + categoryId;
        redisService.del(key);
    }

    private void refreshRedisProdStock(Long shopId, Long productId, BigDecimal stockNumber) {
        String key = StrUtil.format(SHOP_PRODUCT_STOCK, shopId, productId);
        if (NumberUtil.isLessOrEqual(stockNumber, BigDecimal.ZERO)) {
            redisService.del(key);
        } else {
            redisService.set(key, stockNumber.intValue());
        }
    }
}