package cn.iocoder.yudao.module.member.service.storegoodsinventory;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.member.controller.admin.storegoodsinventory.vo.AddReqVO;
import cn.iocoder.yudao.module.member.controller.admin.storegoodsinventory.vo.GoodsInfoReqVO;
import cn.iocoder.yudao.module.member.controller.admin.storegoodsinventory.vo.StoreGoodsInventoryPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.storegoodsinventory.vo.StoreGoodsInventorySaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.storegoods.StoreGoodsDO;
import cn.iocoder.yudao.module.member.dal.dataobject.storegoodsinventory.StoreGoodsInventoryDO;
import cn.iocoder.yudao.module.member.dal.mysql.storegoods.StoreGoodsMapper;
import cn.iocoder.yudao.module.member.dal.mysql.storegoodsinventory.StoreGoodsInventoryMapper;
import cn.iocoder.yudao.module.member.enums.InventoryTypeEnum;
import cn.iocoder.yudao.module.member.service.amount.LockManager;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.STORE_GOODS_INVENTORY_NOT_EXISTS;
import static cn.iocoder.yudao.module.member.service.amount.LockManager.getStoreOrderLock;

/**
 * 商品库存 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class StoreGoodsInventoryServiceImpl implements StoreGoodsInventoryService {

    @Resource
    private StoreGoodsInventoryMapper storeGoodsInventoryMapper;
    @Resource
    private StoreGoodsMapper storeGoodsMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createStoreGoodsInventory(@Valid AddReqVO createReqVO) {
        Integer id = null;
        synchronized (getStoreOrderLock(LockManager.INVENTORY_KEY)) {
            List<GoodsInfoReqVO> list = createReqVO.getList();
            for (GoodsInfoReqVO vo : list) {
                LambdaQueryWrapper<StoreGoodsInventoryDO> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(StoreGoodsInventoryDO::getGoodsId, vo.getGoodsId())
                        .eq(StoreGoodsInventoryDO::getCarteenId, vo.getCarteenId());
                List<StoreGoodsInventoryDO> storeGoodsInventoryDOS = storeGoodsInventoryMapper.selectList(wrapper);
                if (InventoryTypeEnum.IN.getCode().equals(createReqVO.getType())) {
                    if (CollectionUtil.isNotEmpty(storeGoodsInventoryDOS)) {
                        StoreGoodsInventoryDO storeGoodsInventoryDO = storeGoodsInventoryDOS.get(0);
                        storeGoodsInventoryDO.setNumber(storeGoodsInventoryDO.getNumber() + vo.getNumber());
                        storeGoodsInventoryDO.setWeight(storeGoodsInventoryDO.getWeight() + vo.getWeight());
                        storeGoodsInventoryMapper.updateById(storeGoodsInventoryDO);
                        id = storeGoodsInventoryDO.getId();
                    }
                } else {// 出库
                    if (CollectionUtil.isEmpty(storeGoodsInventoryDOS)) {
                        throw exception(STORE_GOODS_INVENTORY_NOT_EXISTS);
                    }
                    StoreGoodsInventoryDO storeGoodsInventoryDO = storeGoodsInventoryDOS.get(0);
                    if (storeGoodsInventoryDO.getNumber() < vo.getNumber()) {
                        StoreGoodsDO storeGoodsDO = storeGoodsMapper.selectById(storeGoodsInventoryDO.getGoodsId());
                        throw exception(new ErrorCode(1_004_019_001, storeGoodsDO.getGoodsName()+"商品库存不足"));
                    }
                    if (storeGoodsInventoryDO.getWeight() < vo.getWeight()) {
                        StoreGoodsDO storeGoodsDO = storeGoodsMapper.selectById(storeGoodsInventoryDO.getGoodsId());
                        throw exception(new ErrorCode(1_004_019_001, storeGoodsDO.getGoodsName()+"商品库存不足"));
                    }
                    storeGoodsInventoryDO.setNumber(storeGoodsInventoryDO.getNumber() - vo.getNumber());
                    storeGoodsInventoryDO.setWeight(storeGoodsInventoryDO.getWeight() - vo.getWeight());
                    storeGoodsInventoryMapper.updateById(storeGoodsInventoryDO);
                    id = storeGoodsInventoryDO.getId();
                }
            }
        }
        // 返回
        return id;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createStoreGoodsInventoryBySale(AddReqVO createReqVO) {
        List<GoodsInfoReqVO> list = createReqVO.getList();
        for (GoodsInfoReqVO vo : list) {
            LambdaQueryWrapper<StoreGoodsInventoryDO> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(StoreGoodsInventoryDO::getGoodsId, vo.getGoodsId())
                    .eq(StoreGoodsInventoryDO::getCarteenId, vo.getCarteenId());
            List<StoreGoodsInventoryDO> storeGoodsInventoryDOS = storeGoodsInventoryMapper.selectList(wrapper);

            if (CollectionUtil.isNotEmpty(storeGoodsInventoryDOS)) {
                StoreGoodsInventoryDO storeGoodsInventoryDO = storeGoodsInventoryDOS.get(0);
                storeGoodsInventoryDO.setNumber(storeGoodsInventoryDO.getNumber());
                storeGoodsInventoryDO.setWeight(storeGoodsInventoryDO.getWeight());
                storeGoodsInventoryMapper.updateById(storeGoodsInventoryDO);
            } else {
                StoreGoodsInventoryDO storeGoodsInventory = BeanUtils.toBean(vo, StoreGoodsInventoryDO.class);
                storeGoodsInventoryMapper.insert(storeGoodsInventory);
            }
        }
    }

    @Override
    public void updateStoreGoodsInventory(StoreGoodsInventorySaveReqVO updateReqVO) {
        // 校验存在
        validateStoreGoodsInventoryExists(updateReqVO.getId());
        // 更新
        StoreGoodsInventoryDO updateObj = BeanUtils.toBean(updateReqVO, StoreGoodsInventoryDO.class);
        storeGoodsInventoryMapper.updateById(updateObj);
    }

    @Override
    public void deleteStoreGoodsInventory(Integer id) {
        // 校验存在
        validateStoreGoodsInventoryExists(id);
        // 删除
        storeGoodsInventoryMapper.deleteById(id);
    }

    private void validateStoreGoodsInventoryExists(Integer id) {
        if (storeGoodsInventoryMapper.selectById(id) == null) {
            throw exception(STORE_GOODS_INVENTORY_NOT_EXISTS);
        }
    }

    @Override
    public StoreGoodsInventoryDO getStoreGoodsInventory(Integer id) {
        return storeGoodsInventoryMapper.selectById(id);
    }

    @Override
    public PageResult<StoreGoodsInventoryDO> getStoreGoodsInventoryPage(StoreGoodsInventoryPageReqVO pageReqVO) {
        if (StrUtil.isNotBlank(pageReqVO.getGoodsName())){
            List<StoreGoodsDO> storeGoodsDOS = storeGoodsMapper.selectList(Wrappers.<StoreGoodsDO>lambdaQuery()
                    .like(StoreGoodsDO::getGoodsName, pageReqVO.getGoodsName()));
            if(CollectionUtil.isNotEmpty(storeGoodsDOS)){
                List<Integer> collect = storeGoodsDOS.stream().map(StoreGoodsDO::getGoodsId).collect(Collectors.toList());
                pageReqVO.setGoodsIds(collect);
            }
        }
        return storeGoodsInventoryMapper.selectPage(pageReqVO);
    }

    @Override
    public Integer getInventory(Integer goodsId, Long carteenId) {
        List<StoreGoodsInventoryDO> list = storeGoodsInventoryMapper.selectList(Wrappers.<StoreGoodsInventoryDO>lambdaQuery()
                .eq(StoreGoodsInventoryDO::getGoodsId, goodsId)
                .eq(StoreGoodsInventoryDO::getCarteenId, carteenId));
        if (CollectionUtil.isNotEmpty(list)) {
            return list.get(0).getNumber();
        }
        return 0;
    }

    @Override
    public Map<Integer, Integer> getInventoryList(List<Integer> goodsIds, Long carteenId) {
        List<StoreGoodsInventoryDO> list = storeGoodsInventoryMapper.selectList(Wrappers.<StoreGoodsInventoryDO>lambdaQuery()
                .in(StoreGoodsInventoryDO::getGoodsId, goodsIds)
                .eq(StoreGoodsInventoryDO::getCarteenId, carteenId));
        if (CollectionUtil.isNotEmpty(list)) {
            return list.stream().collect(Collectors.toMap(StoreGoodsInventoryDO::getGoodsId,StoreGoodsInventoryDO::getNumber));
        }

        return Collections.emptyMap();
    }

    @Override
    public void deleteByGoodsId(Integer goodsId, Long carteenId) {
        storeGoodsInventoryMapper.delete(Wrappers.<StoreGoodsInventoryDO>lambdaUpdate().eq(StoreGoodsInventoryDO::getGoodsId, goodsId)
                .eq(StoreGoodsInventoryDO::getCarteenId, carteenId));
    }
}