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

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procure.BpmOAProcureListEditReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procurepay.BpmOAProcurePayItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procurepay.BpmOAProcurePayPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procurepay.BpmOAProcurePaySaveReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.upload.UploadUserFile;
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAProcurePayConvert;
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAProcurePayItemConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProcureDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProcurePayDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProcurePayItemDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAProcureMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAProcurePayItemMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAProcurePayMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 采购支付 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class BpmOAProcurePayServiceImpl extends BpmOABaseService implements BpmOAProcurePayService {

    @Resource
    private BpmOAProcurePayMapper oAProcurePayMapper;
    @Resource
    private BpmOAProcurePayItemMapper oaProcurePayItemMapper;

    @Resource
    private BpmOAProcureMapper oaProcureMapper;
    @Resource
    private BpmOAProcureService oaProcureService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private BpmProcessInstanceApi processInstanceApi;
    @Resource
    private BpmModelService modelService;
    @Resource
    private BpmProcessInstanceExtMapper processInstanceExtMapper;
    @Resource
    @Lazy // 解决循环依赖
    private BpmProcessInstanceService bpmProcessInstanceService;

    /**
     * OA 采购支付对应的流程定义 KEY
     */
    public static final String PROCESS_KEY = "oa_procure_pay";

    @Override
    public Long createOAProcurePay(BpmOAProcurePaySaveReqVO createReqVO) {
        Long userId = WebFrameworkUtils.getLoginUserId();
        createReqVO.setUserId(userId);
        // 采购支付对象转换
        BpmOAProcurePayDO oAProcurePay = BpmOAProcurePayConvert.INSTANCE.convert(createReqVO);
        oAProcurePayMapper.insert(oAProcurePay);
        // 子列表转换
        List<BpmOAProcurePayItemDO> items = BpmOAProcurePayItemConvert.INSTANCE.convert(createReqVO.getItems());
        for (BpmOAProcurePayItemDO item : items) {
            item.setBpmOaProcurePayId(oAProcurePay.getId());
            item.setUserId(userId);
        }
        oaProcurePayItemMapper.insertBatch(items);

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

        // 将工作流的编号，更新到 OA 采购单中
        oAProcurePayMapper.updateById(new BpmOAProcurePayDO().setId(oAProcurePay.getId()).setProcessInstanceId(processInstanceId));

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

    @Override
    public void updateOAProcurePay(BpmOAProcurePaySaveReqVO updateReqVO) {
        // 更新
        BpmOAProcurePayDO updateObj = BeanUtils.toBean(updateReqVO, BpmOAProcurePayDO.class);
        oAProcurePayMapper.updateById(updateObj);
    }

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

    @Override
    public BpmOAProcurePayDO getOAProcurePay(Long id) {
        BpmOAProcurePayDO bpmOAProcurePayDO = oAProcurePayMapper.selectById(id);
        List<BpmOAProcurePayItemRespVO> items = oaProcurePayItemMapper.getByProcurePayId(id);
        bpmOAProcurePayDO.setItems(items);
        return bpmOAProcurePayDO;
    }

    @Override
    public PageResult<BpmOAProcurePayDO> getOAProcurePayPage(BpmOAProcurePayPageReqVO pageReqVO) {
        return oAProcurePayMapper.selectPage(pageReqVO);
    }

    @Override
    public List<BpmOAProcureDO> getAvailablePurchaseOrders() {
        //获取当前登录用户id
        Long userId = WebFrameworkUtils.getLoginUserId();
        //查询当前登录用户所在部门所有用户id
        CommonResult<List<Long>> userIdsResult = adminUserApi.getUserIdsByUserIdGroupByDept(userId);
        List<Long> userIds = userIdsResult.getData();
        //根据用户ids 获取所有可用采购单
        return oaProcureMapper.selectList(new LambdaQueryWrapperX<BpmOAProcureDO>()
                .in(BpmOAProcureDO::getUserId, userIds)
                .eq(BpmOAProcureDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult())
                .eq(BpmOAProcureDO::getPayFlag, BpmOAProcureDO.FLAG_FALSE)
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateEvectionResult(String processInstanceId, Long id, Integer result) {
        //获取采购申请ids
        List<BpmOAProcurePayItemRespVO> items = oaProcurePayItemMapper.getByProcurePayId(id);
        // -- 这边要处理下
        // -- 审核通过 （最后节点）
        if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) {
            ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId);
            if (instance.isEnded() && !items.isEmpty()) {
                List<Long> ids = items.stream().map(BpmOAProcurePayItemRespVO::getBpmOaProcureId).collect(Collectors.toList());
                //所有关联的采购申请改为 未支付状态
                oaProcureService.updatePayFlagByIds(
                        new BpmOAProcureListEditReqVO()
                                .setPayFlag(BpmOAProcureDO.FLAG_TRUE)
                                .setProcureIds(ids)
                );
            }
        }
        // -- 自己取消
        // -- 审核拒绝
        //所有关联的采购申请改为 未支付状态
        if (BpmProcessInstanceResultEnum.REJECT.getResult().equals(result)
                || BpmProcessInstanceResultEnum.CANCEL.getResult().equals(result)
                || BpmProcessInstanceResultEnum.BACK.getResult().equals(result)) {
            if (!items.isEmpty()) {
                List<Long> ids = items.stream().map(BpmOAProcurePayItemRespVO::getBpmOaProcureId).collect(Collectors.toList());
                //所有关联的采购申请改为 未支付状态
                oaProcureService.updatePayFlagByIds(
                        new BpmOAProcureListEditReqVO()
                                .setPayFlag(BpmOAProcureDO.FLAG_FALSE)
                                .setProcureIds(ids)
                );
            }
        }
        oAProcurePayMapper.updateById(new BpmOAProcurePayDO().setId(id).setResult(result));
    }

}