package ink.wgink.module.activiti.service.activiti.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.SearchException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.activiti.pojo.vos.ActivitiVO;
import ink.wgink.module.activiti.service.activiti.IActivitiService;
import ink.wgink.pojo.result.SuccessResultList;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: ActivitiServiceImpl
 * @Description: activiti
 * @Author: WangGeng
 * @Date: 2021/7/11 16:46
 * @Version: 1.0
 **/
@Service
public class ActivitiServiceImpl extends DefaultBaseService implements IActivitiService {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RuntimeService runtimeService;

    @Override
    public String create(ActivitiVO activitiVO) throws UnsupportedEncodingException {
        long count = repositoryService.createModelQuery().modelName(activitiVO.getModelName()).modelKey(activitiVO.getModelKey()).modelVersion(activitiVO.getModelVersion()).count();
        if (count >= 1) {
            throw new SearchException("模型已经存在");
        }
        Model model = repositoryService.newModel();
        model.setName(activitiVO.getModelName());
        model.setKey(activitiVO.getModelKey());
        model.setMetaInfo(createModelMetaInfo(activitiVO));
        LOG.debug("保存模型");
        repositoryService.saveModel(model);
        addModelEditorSource(model.getId());
        return model.getId();
    }

    @Override
    public void delete(String modelId) {
        Model model = repositoryService.getModel(modelId);
        if (model == null) {
            throw new SearchException("模型不存在");
        }
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processDefinitionKey(model.getKey()).singleResult();
        // 删除模型实例
        if (processInstance != null) {
            runtimeService.deleteProcessInstance(processInstance.getId(), "");
            historyService.deleteHistoricProcessInstance(processInstance.getId());
        }
        //删除模型模型
        repositoryService.deleteModel(modelId);
    }

    @Override
    public void publish(String modelId) throws IOException {
        Model model = repositoryService.getModel(modelId);
        if (model == null) {
            throw new SearchException("模型不存在");
        }
        byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
        if (modelEditorSource == null) {
            throw new SearchException("模型数据不存在");
        }
        JsonNode modelNode = new ObjectMapper().readTree(modelEditorSource);
        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(modelNode);
        Deployment deployment = repositoryService.createDeployment()
                .name(model.getName())
                .key(model.getKey())
                .addBpmnModel(model.getKey() + ".bpmn20.xml", bpmnModel)
                .deploy();
        model.setDeploymentId(deployment.getId());
        repositoryService.saveModel(model);
    }

    @Override
    public void revokePublish(String modelId) {
        Model modelData = repositoryService.getModel(modelId);
        if (modelData == null) {
            throw new SearchException("模型不存在");
        }
        /**
         * 参数不加true:为普通删除，如果当前规则下有正在执行的流程，则抛异常
         * 参数加true:为级联删除,会删除和当前规则相关的所有信息，包括历史
         */
        repositoryService.deleteDeployment(modelData.getDeploymentId(), true);
    }

    @Override
    public List<Model> list() {
        return repositoryService.createModelQuery().list();
    }

    @Override
    public SuccessResultList<List<Model>> listPage(int page, int rows) {
        ModelQuery modelQuery = repositoryService.createModelQuery();
        List<Model> models = modelQuery.listPage(page - 1, rows);
        return new SuccessResultList<>(models, page, modelQuery.count());
    }

    /**
     * 创建模型信息
     *
     * @param activitiVO
     * @return
     */
    private String createModelMetaInfo(ActivitiVO activitiVO) {
        JSONObject metaInfo = new JSONObject();
        metaInfo.put(ModelDataJsonConstants.MODEL_NAME, activitiVO.getModelName());
        metaInfo.put(ModelDataJsonConstants.MODEL_DESCRIPTION, activitiVO.getModelDescription());
        metaInfo.put(ModelDataJsonConstants.MODEL_REVISION, activitiVO.getModelVersion());
        return metaInfo.toString();
    }

    /**
     * 添加模型时完善ModelEditorSource
     *
     * @param modelId
     */
    private void addModelEditorSource(String modelId) throws UnsupportedEncodingException {
        LOG.info("添加模型时完善ModelEditorSource入参模型ID：{}", modelId);
        JSONObject editorObject = new JSONObject();
        editorObject.put("id", "canvas");
        editorObject.put("resourceId", "canvas");

        JSONObject stencilSetObject = new JSONObject();
        stencilSetObject.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");

        editorObject.put("stencilset", stencilSetObject);
        repositoryService.addModelEditorSource(modelId, editorObject.toString().getBytes(ISystemConstant.CHARSET_UTF8));
    }

}
