package jnpf.personnels.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.base.entity.SuperBaseEntity;
import jnpf.model.personnels.dto.goods.FtbPersonnelsGoodsReceiveAddDTO;
import jnpf.model.personnels.dto.goods.FtbPersonnelsGoodsReceiveQueryDTO;
import jnpf.model.personnels.dto.goods.FtbPersonnelsGoodsReceiveReturnDTO;
import jnpf.model.personnels.dto.goods.FtbPersonnelsGoodsReceiveUpdateDTO;
import jnpf.model.personnels.po.FtbPersonnelsGoods;
import jnpf.model.personnels.po.FtbPersonnelsGoodsReceive;
import jnpf.model.personnels.vo.goods.FtbPersonnelsGoodsReceiveDetailsVO;
import jnpf.model.personnels.vo.goods.FtbPersonnelsGoodsReceivePageVO;
import jnpf.model.personnels.vo.goods.PersonnelsGoodsDistributedLock;
import jnpf.permission.V2UserApi;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.personnels.mapper.FtbPersonnelsGoodsMapper;
import jnpf.personnels.mapper.FtbPersonnelsGoodsReceiveMapper;
import jnpf.personnels.service.FtbPersonnelsGoodsReceiveService;
import jnpf.util.UserProvider;
import org.jetbrains.annotations.NotNull;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
*
*
*@Author: peng.hao
*@create: 2025/9/11
*
*/
@Service
public class FtbPersonnelsGoodsReceiveServiceImpl implements FtbPersonnelsGoodsReceiveService {

    @Resource
    private FtbPersonnelsGoodsReceiveMapper ftbPersonnelsGoodsReceiveMapper;
    @Resource
    private FtbPersonnelsGoodsMapper ftbPersonnelsGoodsMapper;
    @Resource
    private Redisson redisson;
    @Resource
    private V2UserApi v2UserApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(List<FtbPersonnelsGoodsReceiveAddDTO> form) {
        List<String> goodIds = form.stream()
                .flatMap(ftbPersonnelsGoodsReceiveAddDTO -> ftbPersonnelsGoodsReceiveAddDTO.getItemsAreCollected().stream())
                .map(FtbPersonnelsGoodsReceiveAddDTO.ItemsAreCollected::getGoodsId)
                .distinct()
                .collect(Collectors.toList());
        LambdaQueryWrapper<FtbPersonnelsGoods> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(FtbPersonnelsGoods::getId, goodIds);
        queryWrapper.eq(FtbPersonnelsGoods::getEnableMark, 0);
        List<FtbPersonnelsGoods> ftbPersonnelsGoods = ftbPersonnelsGoodsMapper.selectList(queryWrapper);
        Map<String, FtbPersonnelsGoods> stringFtbPersonnelsGoodsMap = ftbPersonnelsGoods.stream()
                .collect(Collectors.toMap(FtbPersonnelsGoods::getId, Function.identity()));
        // 部分物品被删除，请重新提交！
        if (stringFtbPersonnelsGoodsMap.size() != goodIds.size()) {
            throw new RuntimeException("部分物品被删除，请重新提交！");
        }
        // 如果所选员工的数量和领用数量的乘积数量小于剩余数量，需提示：XX物品剩余数量不足，请重新选择
        Map<String, Long> goodsNumbers = form.stream()
                .flatMap(ftbPersonnelsGoodsReceiveAddDTO -> ftbPersonnelsGoodsReceiveAddDTO.getItemsAreCollected().stream())
                .collect(Collectors.groupingBy(FtbPersonnelsGoodsReceiveAddDTO.ItemsAreCollected::getGoodsId
                        , Collectors.summingLong(FtbPersonnelsGoodsReceiveAddDTO.ItemsAreCollected::getNumber)));
        for (Map.Entry<String, Long> stringLongEntry : goodsNumbers.entrySet()) {
            FtbPersonnelsGoods ftbPersonnelGood = stringFtbPersonnelsGoodsMap.get(stringLongEntry.getKey());
            if (ftbPersonnelGood.getReturnedQuantity() < stringLongEntry.getValue()) {
                throw new RuntimeException(ftbPersonnelGood.getGoodsName() + "物品剩余数量不足，请重新选择");
            }
        }
        List<String> userIds = form.stream().map(FtbPersonnelsGoodsReceiveAddDTO::getUserId).collect(Collectors.toList());
        ActionResult<List<UserBoundVO>> userPrimaryBoundBatch = v2UserApi.getUserPrimaryBoundBatch(userIds, null);
        if (userPrimaryBoundBatch == null || CollUtil.isEmpty(userPrimaryBoundBatch.getData())) {
            throw new RuntimeException("获取员工信息失败！");
        }
        Map<String, UserBoundVO> userBoundVOMap = userPrimaryBoundBatch.getData().stream()
                .collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        form.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setOrgName(userBoundVO.getOrganizeName());
                a.setUserName(userBoundVO.getName());
            }
        });
        // 数据组装
        UserInfo userInfo = UserProvider.getUser();
        List<FtbPersonnelsGoodsReceive> ftbPersonnelsGoodsReceives = new ArrayList<>();
        for (FtbPersonnelsGoodsReceiveAddDTO ftbPersonnelsGoodsReceiveAddDTO : form) {
            for (FtbPersonnelsGoodsReceiveAddDTO.ItemsAreCollected itemsAreCollected : ftbPersonnelsGoodsReceiveAddDTO.getItemsAreCollected()) {
                if (itemsAreCollected.getNumber() == 0) {
                    continue;
                }
                FtbPersonnelsGoodsReceive ftbPersonnelsGoodsReceive = new FtbPersonnelsGoodsReceive();
                ftbPersonnelsGoodsReceive.setOperatorName(userInfo.getUserName());
                ftbPersonnelsGoodsReceive.setUserId(ftbPersonnelsGoodsReceiveAddDTO.getUserId());
                ftbPersonnelsGoodsReceive.setUserName(ftbPersonnelsGoodsReceiveAddDTO.getUserName());
                ftbPersonnelsGoodsReceive.setOrgName(ftbPersonnelsGoodsReceiveAddDTO.getOrgName());
                ftbPersonnelsGoodsReceive.setReceiptTime(ftbPersonnelsGoodsReceiveAddDTO.getReceiptTime());
                ftbPersonnelsGoodsReceive.setRemark(ftbPersonnelsGoodsReceiveAddDTO.getRemark());
                ftbPersonnelsGoodsReceive.setGoodsId(itemsAreCollected.getGoodsId());
                ftbPersonnelsGoodsReceive.setQuantityUse(itemsAreCollected.getNumber());
                FtbPersonnelsGoods ftbPersonnelGood = stringFtbPersonnelsGoodsMap.get(itemsAreCollected.getGoodsId());
                // 是否需要归还（0-否，1-是）
                if (ftbPersonnelGood.getNeedReturn() == 1) {
                    ftbPersonnelsGoodsReceive.setReturnStatus(0);
                } else {
                    ftbPersonnelsGoodsReceive.setReturnStatus(3);
                }
                ftbPersonnelsGoodsReceives.add(ftbPersonnelsGoodsReceive);
                // 扣减库存
                doUpdateInventory(itemsAreCollected.getGoodsId(), -itemsAreCollected.getNumber());
            }
        }
        Db.saveBatch(ftbPersonnelsGoodsReceives);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(FtbPersonnelsGoodsReceiveUpdateDTO form) {
        FtbPersonnelsGoodsReceiveAddDTO.ItemsAreCollected itemsAreCollected = form.getItemsAreCollected().get(0);
        FtbPersonnelsGoodsReceive ftbPersonnelsGoodsReceive = ftbPersonnelsGoodsReceiveMapper.selectById(form.getId());
        // 如果所选员工领用数量小于剩余数量，需提示：XX物品剩余数量不足，请重新选择
        LambdaQueryWrapper<FtbPersonnelsGoods> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FtbPersonnelsGoods::getId, itemsAreCollected.getGoodsId());
        FtbPersonnelsGoods ftbPersonnelGood = ftbPersonnelsGoodsMapper.selectOne(queryWrapper);
        if (ftbPersonnelGood.getReturnedQuantity() < (itemsAreCollected.getNumber() - ftbPersonnelsGoodsReceive.getQuantityUse())
                && !itemsAreCollected.getNumber().equals(ftbPersonnelsGoodsReceive.getQuantityUse())) {
            throw new RuntimeException(ftbPersonnelGood.getGoodsName() + "物品剩余数量不足，请重新提交");
        }
        // 领用数量大于之前的领用数量，扣减库存，小于之前的领用数量，增加库存
        long quantityUse = ftbPersonnelsGoodsReceive.getQuantityUse() - itemsAreCollected.getNumber();
        doUpdateInventory(itemsAreCollected.getGoodsId(), quantityUse);
        LambdaUpdateWrapper<FtbPersonnelsGoodsReceive> updateWrapper = form.convert(form);
        updateWrapper.set(FtbPersonnelsGoodsReceive::getQuantityUse, itemsAreCollected.getNumber());
        updateWrapper.set(FtbPersonnelsGoodsReceive::getOperatorName, UserProvider.getUser().getUserName());
        ftbPersonnelsGoodsReceiveMapper.update(new FtbPersonnelsGoodsReceive(), updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        FtbPersonnelsGoodsReceive ftbPersonnelsGoodsReceive = ftbPersonnelsGoodsReceiveMapper.selectById(id);
        LambdaUpdateWrapper<FtbPersonnelsGoodsReceive> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SuperBaseEntity.SuperIBaseEntity::getId, id);
        updateWrapper.set(FtbPersonnelsGoodsReceive::getEnableMark, 1);
        // 更新库存
        //doUpdateInventory(ftbPersonnelsGoodsReceive.getGoodsId(), ftbPersonnelsGoodsReceive.getQuantityUse() - ftbPersonnelsGoodsReceive.getReturnedQuantity());
        ftbPersonnelsGoodsReceiveMapper.update(new FtbPersonnelsGoodsReceive(), updateWrapper);
    }

    @Override
    public Page<FtbPersonnelsGoodsReceivePageVO> list(Page<FtbPersonnelsGoodsReceivePageVO> page, FtbPersonnelsGoodsReceiveQueryDTO formQueryDTO) {
        page = ftbPersonnelsGoodsReceiveMapper.listPages(page, formQueryDTO);
        return page;
    }

    @Override
    public FtbPersonnelsGoodsReceiveDetailsVO details(String id) {
        FtbPersonnelsGoodsReceive ftbPersonnelsGoodsReceive = ftbPersonnelsGoodsReceiveMapper.selectById(id);
        FtbPersonnelsGoodsReceiveDetailsVO goodsReceiveDetailsVO = FtbPersonnelsGoodsReceiveDetailsVO.convert(ftbPersonnelsGoodsReceive);
        // 物品名称和剩余数量
        FtbPersonnelsGoods ftbPersonnelsGoods = ftbPersonnelsGoodsMapper.selectById(ftbPersonnelsGoodsReceive.getGoodsId());
        goodsReceiveDetailsVO.setGoodsName(ftbPersonnelsGoods.getGoodsName());
        goodsReceiveDetailsVO.setRemainingQuantity(ftbPersonnelsGoods.getReturnedQuantity());
        return goodsReceiveDetailsVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void returnGoods(FtbPersonnelsGoodsReceiveReturnDTO returnDTO) {
        LambdaUpdateWrapper<FtbPersonnelsGoodsReceive> updateWrapper = returnDTO.convert(returnDTO);
        FtbPersonnelsGoodsReceive ftbPersonnelsGoodsReceive = ftbPersonnelsGoodsReceiveMapper.selectById(returnDTO.getId());
        // 校验物品是否已被归还或者部分归还,物品已归还或者部分归还后，提示物品已归还，请勿重复操作！
        if (ftbPersonnelsGoodsReceive.getReturnStatus() == 2) {
            throw new RuntimeException("物品已归还，请勿重复操作！");
        }
        // 增加库存
        doUpdateInventory(ftbPersonnelsGoodsReceive.getGoodsId(), returnDTO.getReturnedQuantity());
        updateWrapper.set(FtbPersonnelsGoodsReceive::getOperatorName, UserProvider.getUser().getUserName());
        ftbPersonnelsGoodsReceiveMapper.update(new FtbPersonnelsGoodsReceive(), updateWrapper);
    }


    /**
     * 更新库存
     *
     * @param goodsId             商品ID
     * @param newReturnedQuantity 新退货数量(正数为增加库存，负数为扣减库存)
     */
    private void doUpdateInventory(String goodsId, Long newReturnedQuantity) {
        String lockGoods = String.format(PersonnelsGoodsDistributedLock.LOCK_KEY_GOODS, goodsId);
        RLock rLock = redisson.getFairLock(lockGoods);
        try {
            // 尝试获取锁，最多等10秒，持有锁10秒后自动释放
            if (!rLock.tryLock(10, 10, java.util.concurrent.TimeUnit.SECONDS)) {
                throw new RuntimeException("当前操作该物品任务过多，请稍后再试");
            }
            // 更新物品信息
            LambdaUpdateWrapper<FtbPersonnelsGoods> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(SuperBaseEntity.SuperIBaseEntity::getId, goodsId);
            String setSql = getSetSql(newReturnedQuantity);
            updateWrapper.setSql(setSql);
            ftbPersonnelsGoodsMapper.update(new FtbPersonnelsGoods(), updateWrapper);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("系统繁忙，请稍后重试", e);
        } finally {
            // 检查当前线程是否持有锁，避免解锁异常
            if (rLock.isHeldByCurrentThread() && rLock.isLocked()) {
                rLock.unlock();
            }
        }
    }

    @NotNull
    private static String getSetSql(Long newReturnedQuantity) {
        String setSql = "";
        if (newReturnedQuantity > 0) {
            // 增加库存：直接相加
            setSql = "F_ReturnedQuantity = F_ReturnedQuantity + " + newReturnedQuantity;
        } else if (newReturnedQuantity < 0) {
            // 扣减库存：确保不会出现负数
            setSql = "F_ReturnedQuantity = CASE WHEN F_ReturnedQuantity >= "
                    + Math.abs(newReturnedQuantity) + " THEN F_ReturnedQuantity - "
                    + Math.abs(newReturnedQuantity) + " ELSE 0 END";
        }
        return setSql;
    }

}
