package cn.iocoder.yudao.module.bpm.service.oa;

import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.assetClaim.BpmOAAssetClaimCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.assetClaim.BpmOAAssetClaimItemSaveVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAAssetClaimDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAAssetClaimItemDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAAssetClaimMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.assetreceive.AssetReceiveApi;
import cn.iocoder.yudao.module.system.api.assetreceive.dto.AssetReceiveSaveDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.engine.runtime.ProcessInstance;
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.HashMap;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_ASSET_NOT_EXISTS;

/**
 * OA 资产申领 Service 实现类
 *
 * @author 符溶馨
 */
@Service
@Validated
public class BpmOAAssetClaimServiceImpl extends BpmOABaseService implements BpmOAAssetClaimService{

    /**
     * OA 资产申领对应的流程定义 KEY
     */
    public static final String PROCESS_KEY = "oa_asset_claim_2";

    @Resource
    private BpmOAAssetClaimMapper assetClaimMapper;

    @Resource
    private BpmOAAssetClaimItemService itemService;

    @Resource
    private BpmProcessInstanceService processInstanceService;

    @Resource
    private BpmHistoryProcessInstanceService historyProcessInstanceService;

    @Resource
    private AssetReceiveApi receiveApi;

    @Resource
    private AdminUserApi userApi;

    @Override
    public Long createAssetClaim(Long userId, BpmOAAssetClaimCreateReqVO createReqVO) {

        //插入OA 现金支出申请
        BpmOAAssetClaimDO assetClaim = BeanUtils.toBean(createReqVO, BpmOAAssetClaimDO.class).setUserId(userId)
                .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
        assetClaimMapper.insert(assetClaim);

        // 同步插入明细数据
        createReqVO.getReceive().forEach(item -> item.setAssetClaimId(assetClaim.getId()));
        itemService.createAssetClaimItem(createReqVO.getReceive());

        // 发起 BPM 流程
        Map<String, Object> processInstanceVariables = new HashMap<>();
        String processInstanceId = processInstanceService.createProcessInstance(userId,
                new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
                        .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(assetClaim.getId())));

        // 将工作流的编号，更新到 OA 现金支出单中
        assetClaimMapper.updateById(new BpmOAAssetClaimDO().setId(assetClaim.getId()).setProcessInstanceId(processInstanceId));

        // 判断是否为重新发起的流程
        if (createReqVO.getProcessInstanceId() != null && createReqVO.getResult() == 3) {

            historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId());
        }

        List<UploadUserFile> fileItems = createReqVO.getFileItems();
        //这里的逻辑，如果fileItems不为空，且有数据，那么说明是上传了附件的，则需要更工作流文件表对应的实例Id
        if (fileItems != null && !fileItems.isEmpty()) {
            uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
        }

        return assetClaim.getId();
    }

    @Override
    public BpmOAAssetClaimDO getAssetClaim(Long id) {

        return assetClaimMapper.selectById(id);
    }

    @Override
    public BpmOAAssetClaimDO getByProcessInstanceId(String processInstanceId) {

        return assetClaimMapper.selectOne(BpmOAAssetClaimDO::getProcessInstanceId, processInstanceId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAssetClaimResult(String processInstanceId, Long id, Integer result) {

        BpmOAAssetClaimDO assetClaim = validateLeaveExists(id);
        // 获取明细数据
        List<BpmOAAssetClaimItemDO> itemDOs = itemService.getAssetClaimItem(id);

        // 获取用户信息
        AdminUserRespDTO userRespDTO = userApi.getUser(assetClaim.getUserId()).getCheckedData();

        //审核通过 （最后节点）
        if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) {

            ProcessInstance instance = processInstanceService.getProcessInstance(processInstanceId);

            if (instance.isEnded()) {

                List<AssetReceiveSaveDTO> receiveDTOs = new ArrayList<>();
                for (BpmOAAssetClaimItemDO itemDO : itemDOs) {

                    receiveDTOs.add(new AssetReceiveSaveDTO()
                            .setUserId(assetClaim.getUserId())
                            .setDeptId(userRespDTO.getDeptId())
                            .setAssetsTypeId(itemDO.getAssetsTypeId())
                            .setAssetsTypeName(itemDO.getAssetsTypeName())
                            .setAssetsNo(itemDO.getAssetsNo())
                            .setAssetsName(itemDO.getAssetsName())
                            .setNum(itemDO.getNum())
                            .setApplyDate(assetClaim.getCreateTime().toLocalDate())
                            .setStatus(0));
                }

                // 批量插入资产领用信息
                receiveApi.createReceive(receiveDTOs);
            }
        }
        assetClaimMapper.updateById(new BpmOAAssetClaimDO().setId(id).setResult(result));
    }

    private BpmOAAssetClaimDO validateLeaveExists(Long id) {
        BpmOAAssetClaimDO assetClaim = assetClaimMapper.selectById(id);
        if (assetClaim == null) {
            throw exception(OA_ASSET_NOT_EXISTS);
        }
        return assetClaim;
    }
}
