package org.jeecg.modules.activiti.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.modules.activiti.mapper.ReModelMapper;
import org.jeecg.modules.activiti.model.entity.ReModelEntity;
import org.jeecg.modules.activiti.service.ReModelService;
import org.jeecg.common.Constant;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

/**
 * 模型实现类
 *
 * @author yao
 * @date 2019/06/12
 */
@Service
public class ReModelServiceImpl extends ServiceImpl<ReModelMapper, ReModelEntity> implements ReModelService {
    @Autowired
    private RepositoryService repositoryService;

    @Override
    public IPage queryPage(Integer pageNo, Integer pageSize, HttpServletRequest req) {

//        String tenantId = req.getHeader("tenant-id");
//        .modelTenantId(tenantId)
        ModelQuery modelQuery = repositoryService.createModelQuery()
                .orderByLastUpdateTime()
                .desc()
                .orderByModelVersion().desc();
        String[] keys = req.getParameterMap().get("key");
        if (!"".equals(keys) && keys != null) {
            String key = keys[0];
            modelQuery.modelKey(key);
        }
        String[] names = req.getParameterMap().get("name");
        if (!"".equals(names) && names != null) {
            String name = names[0];
            modelQuery.modelName(name);
        }
        List<Model> list = modelQuery.listPage((pageNo - 1) * pageSize, pageSize);
        IPage<Model> page = new Page<>(pageNo, pageSize);
        page.setTotal((int) modelQuery.count());

        return page.setRecords(list);
    }

    @Override
    public Model add(ReModelEntity actReModel) throws UnsupportedEncodingException {
        String description = actReModel.getDescription();
        String key = actReModel.getKey();
        String name = actReModel.getName();
        String tenantId = actReModel.getTenantId();
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.set("stencilset", stencilSetNode);
        Model modelData = repositoryService.newModel();

        description = StringUtils.defaultString(description);
        modelData.setKey(StringUtils.defaultString(key));
        modelData.setName(name);
        modelData.setVersion(Integer
                .parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(modelData.getKey()).count() + 1)));

        ObjectNode modelObjectNode = objectMapper.createObjectNode();
        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, modelData.getVersion());
        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelData.setMetaInfo(modelObjectNode.toString());
        modelData.setTenantId(tenantId);
        repositoryService.saveModel(modelData);
        repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));

        return modelData;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result deploy(String id,HttpServletRequest request) {
        String message = "";
        try {
            Model modelData = repositoryService.getModel(id);
            if(StringUtils.isEmpty(modelData.getTenantId())){
                String tenantId = request.getHeader("tenant-id");
                modelData.setTenantId(tenantId);
            }
            byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
            if (bytes == null) {
                return Result.error("模型为空");
            }
            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
            JsonNode editor = new ObjectMapper().readTree(bytes);
            BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editor);
            if (bpmnModel.getProcesses().size() == 0) {
                return Result.error("部署失败，没有设计流程");
            }
            BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
            byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);

            String processName = modelData.getName();
            if (!StringUtils.endsWith(processName, Constant.ACT_BPMN20)) {
                processName += Constant.ACT_BPMN20;
            }
            ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
            Deployment deployment =
                    repositoryService.createDeployment()
                       .name(modelData.getName())
                       .addInputStream(processName, in)
                       .tenantId(modelData.getTenantId())
                       .deploy();
            // 设置流程分类
            modelData.setDeploymentId(deployment.getId());
            repositoryService.saveModel(modelData);
            return Result.OK("部署成功，流程ID=" + modelData.getId());
        } catch (Exception e) {
            throw new CustomException("部署失败", e);
        }
    }

    @Override
    public void export(String id, HttpServletResponse response) {
        try {
            Model modelData = repositoryService.getModel(id);
            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
            JsonNode editor = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
            BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editor);
            BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
            byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);

            ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
            IOUtils.copy(in, response.getOutputStream());
            String filename = URLEncoder.encode(modelData.getName() + ".bpmn20.xml", "UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename=" + filename);
            response.flushBuffer();
        } catch (Exception e) {
            throw new CustomException("导出model的xml文件失败，模型ID=" + id, e);
        }

    }

    @Override
    public void delete(String id) {
        repositoryService.deleteModel(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(String[] ids) {
        for (String id : ids) {
            repositoryService.deleteModel(id);
        }
    }
}
