package com.mortals.flowable.service;

import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSON;
import com.mortals.flowable.factory.FlowServiceFactory;
import com.mortals.xhx.common.code.YesNoEnum;
import com.mortals.xhx.common.pdu.api.ApiRespPdu;
import com.mortals.xhx.common.pdu.flow.FlowProcDefPdu;
import com.mortals.xhx.common.pdu.flow.FlowViewerPdu;
import com.mortals.xhx.feign.flowable.IApiFlowDefinitionFeign;
import com.mortals.xhx.feign.flowable.IApiFlowInstanceFeign;
import lombok.extern.apachecommons.CommonsLog;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.RestController;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 流程实例服务类
 *
 * @author: finegirl
 * @date: 2021/8/2 10:50
 * @description:
 **/
@RestController
@CommonsLog
public class FlowInstanceServiceImpl extends FlowServiceFactory implements IApiFlowInstanceFeign {


    @Override
    public ApiRespPdu<String> startById(String deployId, Map<String, Object> variables) {
        log.info(String.format("startById！deployId:%s,variables:%s", deployId, JSON.toJSONString(variables)));
        ApiRespPdu<String> rsp = new ApiRespPdu<>();
        rsp.setCode(YesNoEnum.YES.getValue());
        try {
            // 设置流程发起人Id到流程中
//            variables.put("initiator",userId);
//            variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
            String id = runtimeService.startProcessInstanceById(deployId, variables).getId();
            rsp.setData(id);
        } catch (Exception e) {
            log.error("流程启动异常：", e);
            rsp.setCode(YesNoEnum.NO.getValue());
            rsp.setMsg("流程启动异常:" + e.getMessage());
        }
        return rsp;
    }

    @Override
    public ApiRespPdu<String> updateState(Integer state, String instanceId) {
        log.info(String.format("！instanceId:%s,state:%s", instanceId, state));

        ApiRespPdu<String> rsp = new ApiRespPdu<>();
        rsp.setCode(YesNoEnum.YES.getValue());
        try {
            // 激活
            if (state == 1) {
                runtimeService.activateProcessInstanceById(instanceId);
            }
            // 挂起
            if (state == 2) {
                runtimeService.suspendProcessInstanceById(instanceId);
            }
        } catch (Exception e) {
            log.error("流程更新状态异常:", e);
            rsp.setCode(YesNoEnum.NO.getValue());
            rsp.setMsg("流程更新状态异常:" + e.getMessage());
        }
        return rsp;
    }

    @Override
    public ApiRespPdu<String> stopProcess(String processId) {
        log.info("中止流程,processId:" + processId);
        ApiRespPdu<String> rsp = new ApiRespPdu<>();
        rsp.setCode(YesNoEnum.YES.getValue());
        try {
            runtimeService.deleteProcessInstance(processId, "中止流程");
        } catch (Exception e) {
            log.error("删除流程状态异常:", e);
            rsp.setCode(YesNoEnum.NO.getValue());
            rsp.setMsg("删除流程状态异常:" + e.getMessage());
        }
        return rsp;
    }

    @Override
    public ApiRespPdu<String> deleteProcess(String instanceId, String deleteReason) {
        log.info(String.format("deleteProcess！instanceId:%s,deleteReason:%s", instanceId, deleteReason));
        ApiRespPdu<String> rsp = new ApiRespPdu<>();
        rsp.setCode(YesNoEnum.YES.getValue());
        try {
            // 查询历史数据
            HistoricProcessInstance historicProcessInstance = getHistoricProcessInstanceById(instanceId);
            if (historicProcessInstance.getEndTime() != null) {
                //当前实例只存在于历史数据中
                historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
                rsp.setMsg("删除历史数据成功，instanceId：" + instanceId);
                return rsp;
            }
            // 删除流程实例
            runtimeService.deleteProcessInstance(instanceId, deleteReason);
            // 删除历史流程实例
            historyService.deleteHistoricProcessInstance(instanceId);
        } catch (Exception e) {
            log.error("删除流程状态异常:", e);
            rsp.setCode(YesNoEnum.NO.getValue());
            rsp.setMsg("删除流程状态异常:" + e.getMessage());
        }
        return rsp;

    }

    @Override
    public ApiRespPdu<List<FlowViewerPdu>> getFlowViewer(String procInsId) {

        log.info(String.format("获取流程执行过程！procInsId:%s", procInsId));
        ApiRespPdu<List<FlowViewerPdu>> rsp = new ApiRespPdu<>();
        rsp.setCode(YesNoEnum.YES.getValue());
        try {
            List<FlowViewerPdu> flowViewerList = new ArrayList<>();
            FlowViewerPdu flowViewerPdu;
            // 获得活动的节点
            List<HistoricActivityInstance> hisActIns = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(procInsId)
                    .orderByHistoricActivityInstanceStartTime()
                    .asc().list();
            for (HistoricActivityInstance activityInstance : hisActIns) {
                if (!"sequenceFlow".equals(activityInstance.getActivityType())) {
                    flowViewerPdu = new FlowViewerPdu();
                    flowViewerPdu.setKey(activityInstance.getActivityId());
                    flowViewerPdu.setCompleted(!Objects.isNull(activityInstance.getEndTime()));
                    flowViewerList.add(flowViewerPdu);
                }
            }


            rsp.setData(flowViewerList);

        } catch (Exception e) {
            log.error("获取流程执行过程异常:", e);
            rsp.setCode(YesNoEnum.NO.getValue());
            rsp.setMsg("获取流程执行过程异常:" + e.getMessage());
        }
        return rsp;
    }

    public HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance =
                historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (Objects.isNull(historicProcessInstance)) {
            throw new FlowableObjectNotFoundException("流程实例不存在: " + processInstanceId);
        }
        return historicProcessInstance;
    }
}
