package cn.iocoder.yudao.module.system.service.assets;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.system.controller.admin.assets.dto.AssetsChangeDTO;
import cn.iocoder.yudao.module.system.controller.admin.assets.dto.RestorationDTO;
import cn.iocoder.yudao.module.system.controller.admin.assets.vo.AssetsSecondmentPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.assets.vo.AssetsSecondmentRespVO;
import cn.iocoder.yudao.module.system.controller.admin.assets.vo.AssetsSecondmentSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.assets.vo.DeptAssetsInOutStockVO;
import cn.iocoder.yudao.module.system.dal.dataobject.assets.AssetsSecondmentDO;
import cn.iocoder.yudao.module.system.dal.dataobject.assets.AssetsSecondmentRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.assets.AssetsTypeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.assets.DeptAssetsDO;
import cn.iocoder.yudao.module.system.dal.mysql.assets.AssetsSecondmentMapper;
import cn.iocoder.yudao.module.system.dal.mysql.assets.AssetsSecondmentRecordMapper;
import cn.iocoder.yudao.module.system.dal.mysql.assets.AssetsTypeMapper;
import cn.iocoder.yudao.module.system.dal.mysql.assets.DeptAssetsMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
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.system.enums.ErrorCodeConstants.MATERIAL_DOES_NOT_EXIST;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.STOCK_EXCEEDS;

/**
 * 资产借调 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class AssetsSecondmentServiceImpl implements AssetsSecondmentService {

    @Resource
    private AssetsSecondmentMapper assetsSecondmentMapper;
    @Resource
    private AssetsTypeMapper assetsTypeMapper;
    @Resource
    private DeptAssetsMapper deptAssetsMapper;
    @Resource
    private AssetsSecondmentRecordMapper assetsSecondmentRecordMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DeptAssetsInOutStockVO createAssetsSecondment(Long secondmentDeptId, List<AssetsSecondmentSaveReqVO> vos) {
        DeptAssetsInOutStockVO deptAssetsInOutStockVO = new DeptAssetsInOutStockVO();
        List<String> errors = new ArrayList<>();
        //借调 - 从部门中获取东西到个人
        List<Long> assetsIds = new ArrayList<>();
        List<Long> useUserIds = new ArrayList<>();
        List<Long> useDeptIds = new ArrayList<>();
        List<Long> principalUserIds = new ArrayList<>();
        for (AssetsSecondmentSaveReqVO vo : vos) {
            assetsIds.add(vo.getAssetsId());
            useUserIds.add(vo.getUseUserId());
            useDeptIds.add(vo.getUseDeptId());
            principalUserIds.add(vo.getPrincipalUserId());
        }
        if (assetsIds.isEmpty()) {
            throw exception(MATERIAL_DOES_NOT_EXIST);
        }
        // 将vos根据资产id分组 并且合并数量
        Map<Long, List<AssetsSecondmentSaveReqVO>> map = vos.stream().collect(Collectors.groupingBy(AssetsSecondmentSaveReqVO::getAssetsId));
        List<AssetsChangeDTO> deptAssetsDOS = deptAssetsMapper.selectAssetsChangeByIds(assetsIds, secondmentDeptId);
        Map<Long, AssetsChangeDTO> deptAssetsMap = deptAssetsDOS.stream().collect(Collectors.toMap(AssetsChangeDTO::getAssetsId, v -> v));

        //查询部门借调信息
        List<AssetsSecondmentDO> assetsSecondmentDOS = assetsSecondmentMapper.selectList(
                new LambdaQueryWrapper<AssetsSecondmentDO>()
                        .in(AssetsSecondmentDO::getAssetsId, assetsIds)
                        .in(AssetsSecondmentDO::getUseUserId, useUserIds)
                        .in(AssetsSecondmentDO::getUseDeptId, useDeptIds)
                        .in(AssetsSecondmentDO::getPrincipalUserId, principalUserIds)
        );
        // -- 分组
        Map<String, AssetsSecondmentDO> assetsSecondmentMap = assetsSecondmentDOS.stream().collect(Collectors.toMap(a -> a.getAssetsId() + "_" + a.getUseUserId() + "_" + a.getUseDeptId() + "_" + a.getPrincipalUserId(), v -> v));

        List<AssetsSecondmentDO> saveList = new ArrayList<>();
        List<AssetsSecondmentDO> editList = new ArrayList<>();
        List<AssetsSecondmentRecordDO> records = new ArrayList<>();
        List<DeptAssetsDO> editDeptAssets = new ArrayList<>();
        // -- 根据资产过滤
        for (Map.Entry<Long, List<AssetsSecondmentSaveReqVO>> entry : map.entrySet()) {
            List<AssetsSecondmentSaveReqVO> values = entry.getValue();
            AssetsChangeDTO assetsChangeDTO = deptAssetsMap.get(entry.getKey());
            if (assetsChangeDTO == null) {
                throw exception(MATERIAL_DOES_NOT_EXIST);
            }
            int sum = values.stream().mapToInt(AssetsSecondmentSaveReqVO::getNum).sum();
            if (assetsChangeDTO.getStock() < sum) {
                errors.add("资产名称为:" + assetsChangeDTO.getName() + "库存超出!");
                continue;
            }
            DeptAssetsDO deptAssetsDO = new DeptAssetsDO();
            deptAssetsDO.setId(assetsChangeDTO.getId());
            if (assetsChangeDTO.getType().equals(AssetsTypeDO.TYPE_QUANTITY)) {
                deptAssetsDO.setStock(assetsChangeDTO.getStock() - sum);
            } else {
                deptAssetsDO.setStatus(1);
            }
            editDeptAssets.add(deptAssetsDO);

            // -- 遍历当前资产下的借调信息
            for (AssetsSecondmentSaveReqVO item : entry.getValue()) {
                AssetsSecondmentDO assetsSecondmentDO = assetsSecondmentMap.get(item.getAssetsId() + "_" + item.getUseUserId() + "_" + item.getUseDeptId() + "_" + item.getPrincipalUserId());
                if (assetsSecondmentDO == null) {
                    assetsSecondmentDO = new AssetsSecondmentDO();
                    assetsSecondmentDO.setId(IdWorker.getId());
                    assetsSecondmentDO.setAssetsId(item.getAssetsId());
                    assetsSecondmentDO.setUseUserId(item.getUseUserId());
                    assetsSecondmentDO.setUseDeptId(item.getUseDeptId());
                    assetsSecondmentDO.setPrincipalUserId(item.getPrincipalUserId());
                    assetsSecondmentDO.setNum(item.getNum());
                    assetsSecondmentDO.setSecondmentDeptId(secondmentDeptId);
                    saveList.add(assetsSecondmentDO);
                } else {
                    assetsSecondmentDO.setNum(assetsSecondmentDO.getNum() + item.getNum());
                    editList.add(assetsSecondmentDO);
                }
                AssetsSecondmentRecordDO assetsSecondmentRecordDO = new AssetsSecondmentRecordDO();
                assetsSecondmentRecordDO.setAssetsId(item.getAssetsId());
                assetsSecondmentRecordDO.setUseUserId(item.getUseUserId());
                assetsSecondmentRecordDO.setUseDeptId(item.getUseDeptId());
                assetsSecondmentRecordDO.setPrincipalUserId(item.getPrincipalUserId());
                assetsSecondmentRecordDO.setSecondmentDeptId(secondmentDeptId);
                assetsSecondmentRecordDO.setAssetSecondmentId(assetsSecondmentDO.getId());
                assetsSecondmentRecordDO.setNum(item.getNum());
                assetsSecondmentRecordDO.setRemark(item.getRemark());
                assetsSecondmentRecordDO.setStatus(0);
                records.add(assetsSecondmentRecordDO);
            }
        }
        if (!errors.isEmpty()) {
            deptAssetsInOutStockVO.setErrors(errors);
            return deptAssetsInOutStockVO;
        }
        if (!saveList.isEmpty()) {
            assetsSecondmentMapper.insertBatch(saveList);
        }
        if (!editList.isEmpty()) {
            assetsSecondmentMapper.updateBatch(editList);
        }
        if (!records.isEmpty()) {
            assetsSecondmentRecordMapper.insertBatch(records);
        }
        if (!editDeptAssets.isEmpty()) {
            deptAssetsMapper.updateBatch(editDeptAssets);
        }
        return deptAssetsInOutStockVO;
    }

    @Override
    public void updateAssetsSecondment(AssetsSecondmentSaveReqVO updateReqVO) {
        // 更新
        AssetsSecondmentDO updateObj = BeanUtils.toBean(updateReqVO, AssetsSecondmentDO.class);
        assetsSecondmentMapper.updateById(updateObj);
    }

    @Override
    public void deleteAssetsSecondment(Long id) {
        // 删除
        assetsSecondmentMapper.deleteById(id);
    }

    @Override
    public AssetsSecondmentDO getAssetsSecondment(Long id) {
        return assetsSecondmentMapper.selectById(id);
    }

    @Override
    public PageResult<AssetsSecondmentRespVO> getAssetsSecondmentPage(AssetsSecondmentPageReqVO pageReqVO) {
        IPage<AssetsSecondmentRespVO> vos = assetsSecondmentMapper.getAssetsSecondmentPage(pageReqVO, MyBatisUtils.buildPage(pageReqVO));
        return new PageResult<>(vos.getRecords(), vos.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restoration(RestorationDTO dto) {
        AssetsSecondmentDO assetsSecondmentDO = assetsSecondmentMapper.selectById(dto.getId());
        if (assetsSecondmentDO.getNum() < dto.getNum()) {
            throw exception(STOCK_EXCEEDS);
        }
        // - 归还的部门新增
        DeptAssetsDO deptAssetsDO = deptAssetsMapper.selectOne(new LambdaQueryWrapper<DeptAssetsDO>()
                .eq(DeptAssetsDO::getDeptId, assetsSecondmentDO.getSecondmentDeptId())
                .eq(DeptAssetsDO::getAssetsId, assetsSecondmentDO.getAssetsId()));
        if (deptAssetsDO == null) {
            throw exception(MATERIAL_DOES_NOT_EXIST);
        }
        AssetsTypeDO assetsTypeDO = assetsTypeMapper.getByAssetsId(assetsSecondmentDO.getAssetsId());
        if (assetsTypeDO.getType().equals(AssetsTypeDO.TYPE_QUANTITY)) {
            if (assetsSecondmentDO.getNum() - dto.getNum() <= 0) {
                assetsSecondmentMapper.deleteById(dto.getId());
            } else {
                assetsSecondmentDO.setNum(assetsSecondmentDO.getNum() - dto.getNum());
                assetsSecondmentMapper.updateById(assetsSecondmentDO);
            }
            deptAssetsDO.setStock(deptAssetsDO.getStock() + dto.getNum());
            deptAssetsMapper.updateById(deptAssetsDO);
        } else {
            assetsSecondmentMapper.deleteById(dto.getId());
            deptAssetsMapper.updateById(deptAssetsDO.setStatus(0));
        }

        AssetsSecondmentRecordDO assetsSecondmentRecordDO = new AssetsSecondmentRecordDO();
        assetsSecondmentRecordDO.setAssetsId(assetsSecondmentDO.getAssetsId());
        assetsSecondmentRecordDO.setUseUserId(assetsSecondmentDO.getUseUserId());
        assetsSecondmentRecordDO.setUseDeptId(assetsSecondmentDO.getUseDeptId());
        assetsSecondmentRecordDO.setPrincipalUserId(assetsSecondmentDO.getPrincipalUserId());
        assetsSecondmentRecordDO.setSecondmentDeptId(assetsSecondmentDO.getSecondmentDeptId());
        assetsSecondmentRecordDO.setAssetSecondmentId(dto.getId());
        assetsSecondmentRecordDO.setNum(dto.getNum());
        assetsSecondmentRecordDO.setRemark(dto.getRemark());
        assetsSecondmentRecordDO.setStatus(1);
        assetsSecondmentRecordMapper.insert(assetsSecondmentRecordDO);
    }
}