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

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
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.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.imprest.BpmOAImprestCreateReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.financialpayment.FinancialPaymentDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAImprestMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.financialpayment.FinancialPaymentService;
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.bank.BankApi;
import cn.iocoder.yudao.module.system.api.bank.dto.BankRespDTO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
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_IMPREST_NOT_EXISTS;

/**
 * OA 备用金申请 Service 实现类
 *
 * @author 符溶馨
 */
@Service
@Validated
public class BpmOAImprestServiceImpl extends BpmOABaseService implements BpmOAImprestService {

    /**
     * OA 备用金对应的流程定义 KEY
     */
    public static final String PROCESS_KEY = "oa_imprest";

    @Resource
    private BpmOAImprestMapper imprestMapper;

    @Resource
    private BpmProcessInstanceApi processInstanceApi;

    @Resource
    @Lazy // 解决循环依赖
    private BpmProcessInstanceService bpmProcessInstanceService;

    @Resource
    private FinancialPaymentService financialPaymentService;

    @Resource
    private AdminUserApi userApi;

    @Resource
    private DeptApi deptApi;

    @Resource
    private BankApi bankApi;

    @Resource
    private BpmHistoryProcessInstanceService historyProcessInstanceService;

    @Override
    public Long createImprest(Long userId, BpmOAImprestCreateReqVO createReqVO) {

        //插入OA 备用金申请
        BpmOAImprestDO imprest = BeanUtils.toBean(createReqVO, BpmOAImprestDO.class)
                .setUserId(userId)
                .setStatus(BpmOAImprestDO.FLAG_FALSE)
                .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
        imprestMapper.insert(imprest);

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

        // 将工作流的编号，更新到 OA 备用金单中
        imprestMapper.updateById(new BpmOAImprestDO().setId(imprest.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 imprest.getId();
    }

    @Override
    public void updateImprestResult(String processInstanceId, Long id, Integer result) {

        BpmOAImprestDO imprestDO = validateLeaveExists(id);
        imprestMapper.updateById(new BpmOAImprestDO().setId(id).setResult(result));

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

            ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId);

            if (instance.isEnded()) {
                //判断是否有采购报销
                BpmProcessInstanceExtDO processInstance = bpmProcessInstanceService.getProcessInstanceDO(processInstanceId);
                CommonResult<AdminUserRespDTO> user = userApi.getUser(imprestDO.getUserId());

                // 从缓存中部门所属公司信息
                DeptRespDTO deptRespDTO = deptApi.getDept(imprestDO.getCompanyId()).getCheckedData();

                // 获取收款人信息
                BankRespDTO bankRespDTO = new BankRespDTO();
                if (imprestDO.getBankId() != null) {
                    bankRespDTO = bankApi.getBank(imprestDO.getBankId()).getCheckedData();
                }

                // -- 插入到财务支付表中
                financialPaymentService.save(new FinancialPaymentDO()
                        .setUserId(imprestDO.getUserId())
                        .setDeptId(user.getData() == null ? null : user.getData().getDeptId())
                        .setProcessInstanceId(imprestDO.getProcessInstanceId())
                        .setReason(imprestDO.getReason())
                        .setObjectId(id)
                        .setType(2)
                        .setStatus(0)
                        .setAmountPayable(imprestDO.getAmount())
                        .setProcessInstanceName(processInstance.getName())
                        .setBeginTime(processInstance.getCreateTime())
                        .setEndTime(processInstance.getEndTime())
                        .setRecipientName(bankRespDTO != null ? bankRespDTO.getNickname() + "," + bankRespDTO.getBankNo() + "," + bankRespDTO.getBankName() : "")
                        .setCompanyId(deptRespDTO != null ? deptRespDTO.getId() : null)
                );
            }
        }
    }

    private BpmOAImprestDO validateLeaveExists(Long id) {
        BpmOAImprestDO imprestDO = imprestMapper.selectById(id);
        if (imprestDO == null) {
            throw exception(OA_IMPREST_NOT_EXISTS);
        }
        return imprestDO;
    }

    @Override
    public BpmOAImprestDO getImprest(Long id) {

        return imprestMapper.selectById(id);
    }

    @Override
    public BpmOAImprestDO getImprestByUserId(Long userId) {

        //根据user 查询审批通过并且未报销得表单。
        return imprestMapper.selectByUserId(userId);
    }

    @Override
    public BpmOAImprestDO getByProcessInstanceId(String processInstanceId) {
        List<BpmOAImprestDO> list = imprestMapper.selectList(new LambdaQueryWrapper<BpmOAImprestDO>()
                .eq(BpmOAImprestDO::getProcessInstanceId, processInstanceId));
        if (!list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }
}