package com.mortals.xhx.module.flowable.web;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.mortals.framework.common.IBaseEnum;
import com.mortals.framework.common.code.YesNo;
import com.mortals.framework.model.Context;
import com.mortals.framework.model.Result;
import com.mortals.framework.web.BaseCRUDJsonController;
import com.mortals.framework.web.BaseCRUDMappingController;
import com.mortals.xhx.base.system.param.model.ParamEntity;
import com.mortals.xhx.base.system.param.model.ParamQuery;
import com.mortals.xhx.base.system.param.service.ParamService;
import com.mortals.xhx.base.system.upload.service.UploadService;
import com.mortals.xhx.common.code.FlowStateType;
import com.mortals.xhx.common.code.YesNoEnum;
import com.mortals.xhx.common.pdu.flow.DefinitionVoPdu;
import com.mortals.xhx.common.pdu.flow.FlowSaveXmlPdu;
import com.mortals.xhx.common.pdu.flow.FlowTaskVars;
import com.mortals.xhx.common.pdu.flow.FlowTaskVoPdu;
import com.mortals.xhx.common.utils.StringUtils;
import com.mortals.xhx.module.site.model.SiteQuery;
import com.mortals.xhx.module.site.service.SiteService;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import com.mortals.framework.web.BaseCRUDJsonMappingController;
import com.mortals.xhx.module.flowable.model.FlowableDefinitionEntity;
import com.mortals.xhx.module.flowable.service.FlowableDefinitionService;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.text.ParagraphView;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * <p>Title: 流程定义表</p>
 * <p>Description: FlowableDefinitionController  </p>
 * <p>Copyright: Copyright &reg;  </p>
 * <p>Company: </p>
 *
 * @author zxfei
 * @version 1.0.0
 */
@RestController
@RequestMapping("flowable/definition")
public class FlowableDefinitionController extends BaseCRUDJsonMappingController<FlowableDefinitionService, FlowableDefinitionForm, FlowableDefinitionEntity, Long> {

    @Autowired
    private ParamService paramService;
    @Autowired
    private SiteService siteService;

    public FlowableDefinitionController() {
        super.setFormClass(FlowableDefinitionForm.class);
        super.setModuleDesc("流程定义表");
    }

    @Override
    protected void init(HttpServletRequest request, HttpServletResponse response, FlowableDefinitionForm form, Map<String, Object> model, Context context) {
        this.addDict(model, "suspensionState", IBaseEnum.getEnumMap(FlowStateType.class));
        this.addDict(model, "multiple", YesNoEnum.getEnumMap());
        this.addDict(model, "site", siteService.find(new SiteQuery()).stream().collect(Collectors.toMap(x -> x.getId().toString(), y -> y.getSiteName())));
    }

    /**
     * 查询流程定义表
     */
    @PostMapping(value = "list")
    @Override
    public String list(FlowableDefinitionForm form) {
        Map<String, Object> model = new HashMap();
        JSONObject ret = new JSONObject();
        int code = VALUE_RESULT_SUCCESS;
        String busiDesc = "查询" + this.getModuleDesc();
        try {
            Result<FlowableDefinitionEntity> result = this.service.getDefinList(form.getQuery(), form.getPageInfo(), getContext());
            this.init(request, response, form, model, getContext());
            model.put("result", result.getList());
            model.put("pageInfo", result.getPageInfo());
            model.putAll(form.getModel());
            this.recordSysLog(request, busiDesc + " 【成功】");
        } catch (Exception e) {
            log.error("查询流程列表异常", e);
            this.doException(request, busiDesc, model, e);
            code = VALUE_RESULT_FAILURE;
        }

        ret.put("code", code);
        ret.put("query", form.getQuery());
        ret.put("data", model);
        return ret.toJSONString();
    }


    /**
     * 读取流程图片
     */
    @PostMapping(value = "readImage")
    public String readImage(@ApiParam(value = "流程定义id") @RequestParam(value = "deployId") String deployId) {
        JSONObject jsonObject = new JSONObject();
        OutputStream os = null;
        BufferedImage image = null;
        try {
            String base64 = this.getService().readImage(deployId);

            byte[] bytes = Base64.decode(base64);

            //  uploadService.saveFileUpload()
            jsonObject.put("src", VALUE_RESULT_SUCCESS);
            jsonObject.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
        } catch (Exception e) {
            log.error("读取流程图片异常", e);
            jsonObject.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            jsonObject.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return jsonObject.toJSONString();
    }


    @PostMapping(value = "setVars")
    public String setVars(@ApiParam(value = "流程提交参数") @RequestParam Map<String, String> mapParam) {

        JSONObject ret = new JSONObject();
        try {

            mapParam.entrySet().stream().forEach(item -> {
                if (!ObjectUtils.isEmpty(item.getValue()) && !"__mortals_token__".equals(item.getKey())) {
                    List<FlowTaskVars> list = JSON.parseObject(item.getValue(), new TypeReference<List<FlowTaskVars>>() {
                    });
                    //构建提交参数
                    JSONObject jsonObject = new JSONObject();
                    for (FlowTaskVars var : list) {
                        //判断是否并联
                        if (var.getMultiple() == 0) {
                            //判断如果是组 则需要列表获取
                            //key
                            String el = var.getEl();
                            if (!ObjectUtils.isEmpty(el)) {
                                String key = el.substring(2, el.length() - 1);
                                //值
                                String assignee = var.getAssignee();
                                if (ObjectUtils.isEmpty(assignee)) {

                                    if (ObjectUtils.isEmpty(var.getCandidateUsersIds())) {
                                        assignee = var.getCandidateUsersIds();
                                    }

                                    if (ObjectUtils.isEmpty(var.getCandidateGroupsName())) {
                                        assignee = var.getCandidateGroupsName();
                                    }
                                }
                                jsonObject.put(key, assignee);
                            } else {
                                //判断是否为候选人
                                if (!ObjectUtils.isEmpty(var.getCandidateUsers())) {
                                    log.info("候选人");

                                    String key =StringUtils.substringBetween(var.getCandidateUsers().get(0),"{","}");
                                    jsonObject.put(key, var.getCandidateUsersIds());
                                }

                                if (!ObjectUtils.isEmpty(var.getCandidateGroups())) {
                                    log.info("候选组");
                                    String key =StringUtils.substringBetween(var.getCandidateGroups().get(0),"{","}");
                                    jsonObject.put(key, var.getCandidateGroupsName());
                                }
                            }
                        } else {
                            //key
                            String key = var.getEl();
                            if (!ObjectUtils.isEmpty(key)) {
                                JSONArray jsonArray = new JSONArray();
                                jsonArray.addAll(var.getAssigneeList());
                                jsonObject.put(key, jsonArray);
                            } else {
                                //判断是否为候选人
                                if (ObjectUtils.isEmpty(var.getCandidateUsers())) {
                                    log.info("候选人");
                                }

                                if (ObjectUtils.isEmpty(var.getCandidateGroups())) {
                                    log.info("候选组");
                                }
                            }

                        }
                    }


                    ParamQuery paramQuery = new ParamQuery();
                    paramQuery.setParamKey(item.getKey());

                    ParamEntity entity = paramService.selectOne(paramQuery, null);
                    if (ObjectUtils.isEmpty(entity)) {
                        entity = new ParamEntity();
                        entity.setParamKey(item.getKey());
                        entity.setName("流程提交参数");
                        entity.setCreateTime(new Date());
                        entity.setCreateUserId(getCurUser().getId());
                        entity.setCreateUser(getCurUser().getLoginName());
                        entity.setCreateUserName(getCurUser().getRealName());
                    }
                    entity.setParamValue(JSON.toJSONString(jsonObject));
                    if (!ObjectUtils.isEmpty(entity.getId())) {
                        paramService.update(entity);
                    } else {
                        paramService.save(entity);
                    }
                }
            });

            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
        } catch (Exception e) {
            log.error("设置流程提交参数异常", e);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return ret.toJSONString();
    }

    /**
     * 读取流程XML
     */
    @PostMapping(value = "readXml")
    public String readXml(@ApiParam(value = "流程定义id") @RequestParam(value = "deployId") String deployId) {

        log.info("readXml,deployId:" + deployId);
        JSONObject ret = new JSONObject();
        try {
            String Xml = this.getService().readXml(deployId);
            ret.put(KEY_RESULT_DATA, Xml);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
        } catch (Exception e) {
            log.error("读取流程XML异常", e);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return ret.toJSONString();
    }

    /**
     * 保存流程XML
     */
    @PostMapping(value = "saveXml")
    public String saveXml(@ApiParam(value = "流程定义类") @RequestParam Map map) {
        FlowSaveXmlPdu flowSaveXmlPdu = BeanUtil.fillBeanWithMap(map, new FlowSaveXmlPdu(), false);
        JSONObject ret = new JSONObject();
        try {
            String definId = this.getService().saveXml(flowSaveXmlPdu, getContext());
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
            ret.put(KEY_RESULT_MSG, "保存模型XML成功，definitionId:" + definId);
        } catch (Exception e) {
            log.error("保存XML异常", e);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return ret.toJSONString();
    }


    /**
     * 启动流程定义的实例
     */
    @PostMapping(value = "start")
    public String start(@ApiParam(value = "流程定义id") @RequestParam(value = "procDefId") String procDefId,
                        @ApiParam(value = "流程定义类") @RequestParam(value = "data") String data) {

        JSONObject ret = new JSONObject();
        try {
            String proInstanceId = this.getService().start(procDefId, data, getContext());
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
            ret.put(KEY_RESULT_MSG, "部署流程实例成功，proInstanceId:" + proInstanceId);
        } catch (Exception e) {
            log.error("部署流程实例异常", e);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return ret.toJSONString();
    }


    /**
     * 激活/挂起流程
     */
    @PostMapping(value = "updateState")
    public String updateState(@ApiParam(value = "流程定义实体类") DefinitionVoPdu definitionVoPdu) {

        JSONObject ret = new JSONObject();
        try {
            String proInstanceId = this.getService().updateState(definitionVoPdu, getContext());
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
            ret.put(KEY_RESULT_MSG, "挂起/激活流程成功，proInstanceId:" + proInstanceId);
        } catch (Exception e) {
            log.error("挂起/激活流程异常", e);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return ret.toJSONString();
    }


    /**
     * 删除流程定义
     */
    @PostMapping(value = "deleteDefinition")
    public String deleteDefinition(@ApiParam(value = "流程定义实体类") DefinitionVoPdu definitionVoPdu) {

        JSONObject ret = new JSONObject();
        try {
            String deplyId = this.getService().deleteDefinition(definitionVoPdu, getContext());
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
            ret.put(KEY_RESULT_MSG, "删除流程成功，deplyId:" + deplyId);
        } catch (Exception e) {
            log.error("删除流程异常", e);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return ret.toJSONString();
    }


    /**
     * 导入附件
     */
    @PostMapping(value = "upload")
    public String upload(@RequestParam(required = false) String name,
                         @RequestParam(required = false) String category,
                         MultipartFile multipartFile) {

        JSONObject ret = new JSONObject();
        try {

            String xml = IoUtil.readUtf8(multipartFile.getInputStream());

            FlowSaveXmlPdu flowSaveXmlPdu = new FlowSaveXmlPdu();
            flowSaveXmlPdu.setCategory(category);
            flowSaveXmlPdu.setName(name);
            flowSaveXmlPdu.setXml(xml);

            String definId = this.getService().saveXml(flowSaveXmlPdu, getContext());
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
            ret.put(KEY_RESULT_MSG, "导入模型XML成功，definitionId:" + definId);
        } catch (Exception e) {
            log.error("挂起/激活流程异常", e);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return ret.toJSONString();
    }


    @PostMapping(value = "getAllProcessInstanceEl")
    public String getAllProcessInstanceEl(@ApiParam(value = "流程定义key") @RequestParam(value = "processDefinitionKey") String processDefinitionKey) {

        JSONObject ret = new JSONObject();
        try {
            List<FlowTaskVoPdu> list = this.getService().getAllProcessInstanceEl(processDefinitionKey);

            ret.put(KEY_RESULT_DATA, list);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
        } catch (Exception e) {
            log.error("读取流程XML异常", e);
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return ret.toJSONString();
    }

}