package com.fjhx.service.stock.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.constants.ErrorMsgConstant;
import com.fjhx.constants.StockJournalTypeConstant;
import com.fjhx.constants.VLockConstant;
import com.fjhx.entity.stock.Stock;
import com.fjhx.mapper.stock.StockMapper;
import com.fjhx.params.stock.StockVo;
import com.fjhx.service.stock.StockService;
import com.fjhx.utils.Assert;
import com.fjhx.utils.WrapperUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.redis.lock.RedisLockClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Map;

/**
 * <p>
 * 库存 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-11-24
 */
@Service
public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements StockService {

    @Resource
    private RedisLockClient redisLockClient;

    @Autowired
    private StockJournalServiceImpl stockJournalService;

    @Override
    public Page<Stock> getPage(Map<String, Object> condition) {

        QueryWrapper<Stock> wrapper = Wrappers.query();

        WrapperUtil.init(condition, wrapper)
                .createTimeDesc();

        Page<Stock> page = page(condition, wrapper);
        return page;
    }

    @Override
    public void add(StockVo stockVo) {
        save(stockVo);
    }

    @Override
    public void edit(StockVo stockVo) {
        updateById(stockVo);
    }

    @Override
    public void delete(StockVo stockVo) {
        removeById(stockVo.getId());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeQuantity(Long goodsId, Long warehouseId, BigDecimal quantity, Integer detailsType, String remarks) {
        // 分布式锁，粒度为物品id + 仓库id
        Boolean flag = redisLockClient.lockFair(VLockConstant.STOCK_LOCK + goodsId + warehouseId,
                () -> {
                    Stock stock = getOne(q -> q.eq(Stock::getGoodsId, goodsId).eq(Stock::getWarehouseId, warehouseId));

                    // 没有物料存储记录，则创建物料
                    if (stock == null) {
                        if (quantity.compareTo(BigDecimal.ZERO) < 0) {
                            throw new ServiceException("库存不足，出库失败");
                        }

                        stock = new Stock();
                        stock.setGoodsId(goodsId);
                        stock.setQuantity(quantity);
                        stock.setWarehouseId(warehouseId);
                        return save(stock);
                    }

                    BigDecimal newQuantity = stock.getQuantity().add(quantity);
                    if (newQuantity.compareTo(BigDecimal.ZERO) < 0) {
                        throw new ServiceException("库存不足，出库失败");
                    }

                    stock.setQuantity(newQuantity);
                    return updateById(stock);
                });

        Assert.eqTrue(flag, ErrorMsgConstant.SYSTEM_BUSY_ERROR);

        // 添加出入库明细
        stockJournalService.add(
                quantity.compareTo(BigDecimal.ZERO) > 0 ? StockJournalTypeConstant.IN : StockJournalTypeConstant.OUT,
                detailsType,
                goodsId,
                warehouseId,
                quantity.compareTo(BigDecimal.ZERO) > 0 ? quantity : BigDecimal.ZERO.subtract(quantity),
                remarks
        );
    }

}
