package com.njcn.bpm.controller;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.bpm.pojo.dto.BpmModelMetaInfoRespDTO;
import com.njcn.bpm.pojo.param.BpmModelParam;
import com.njcn.bpm.pojo.po.BpmCategory;
import com.njcn.bpm.pojo.po.BpmForm;
import com.njcn.bpm.pojo.vo.BpmModelRespVO;
import com.njcn.bpm.service.IBpmCategoryService;
import com.njcn.bpm.service.IBpmFormService;
import com.njcn.bpm.service.IBpmModelService;
import com.njcn.bpm.service.IBpmProcessDefinitionService;
import com.njcn.bpm.utils.BpmModelConvert;
import com.njcn.bpm.utils.CollectionUtils;
import com.njcn.bpm.utils.JsonUtils;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.constant.OperateType;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.HttpResultUtil;
import com.njcn.common.utils.LogUtil;
import com.njcn.web.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.njcn.bpm.utils.CollectionUtils.convertMap;
import static com.njcn.bpm.utils.CollectionUtils.convertSet;


/**
 * @author hongawen
 */
@RestController
@RequestMapping("/bpm/model")
@Validated
@Slf4j
@Api(tags = "流程模型控制器")
@RequiredArgsConstructor
public class BpmModelController extends BaseController {

    private final IBpmModelService modelService;

    private final IBpmFormService formService;

    private final IBpmCategoryService categoryService;

    private final IBpmProcessDefinitionService processDefinitionService;

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/list")
    @ApiOperation("获得模型分页")
    @ApiImplicitParam(name = "bpmModelQueryParam", value = "查询参数", required = true)
    public HttpResult<Page<BpmModelRespVO>> getModelPage(@RequestBody BpmModelParam.BpmModelQueryParam bpmModelQueryParam) {
        String methodDescribe = getMethodDescribe("list");
        LogUtil.njcnDebug(log, "{}，查询流程表单数据为：{}", methodDescribe, bpmModelQueryParam);
        Page<Model> pageResult = modelService.getModelPage(bpmModelQueryParam);
        if (CollUtil.isEmpty(pageResult.getRecords())) {
            Page<BpmModelRespVO> result = new Page<>();
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
        }
        // 拼接数据
        // 获得 Form 表单
        Set<String> formIds = convertSet(pageResult.getRecords(), model -> {
            BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
            return metaInfo != null ? metaInfo.getFormId() : null;
        });
        Map<String, BpmForm> formMap = formService.getFormMap(formIds);
        // 获得 Category Map
        Map<String, BpmCategory> categoryMap = categoryService.getCategoryMap(
                convertSet(pageResult.getRecords(), Model::getCategory));
        // 获得 Deployment Map
        Set<String> deploymentIds = new HashSet<>();
        pageResult.getRecords().forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId()));

        Map<String, Deployment> deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds);
        // 获得 ProcessDefinition Map
        List<ProcessDefinition> processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds);
        Map<String, ProcessDefinition> processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, BpmModelConvert.INSTANCE.buildModelPage(pageResult, formMap, categoryMap, deploymentMap, processDefinitionMap), methodDescribe);
    }

    @GetMapping("/getById")
    @ApiOperation("根据id获取模型")
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @Parameter(name = "id", description = "编号", required = true)
    public HttpResult<BpmModelRespVO> getById(String id) {
        Model model = modelService.getModel(id);
        String methodDescribe = getMethodDescribe("getById");
        if (model == null) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
        }
        byte[] bpmnBytes = modelService.getModelBpmnXML(id);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, BpmModelConvert.INSTANCE.buildModel(model, bpmnBytes), methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.ADD)
    @PostMapping("/add")
    @ApiOperation("新建模型")
    @ApiImplicitParam(name = "bpmModelParam", value = "模型数据", required = true)
    public HttpResult<String> createModel(@Validated @RequestBody BpmModelParam bpmModelParam) {
        String methodDescribe = getMethodDescribe("createModel");
        String modelId = modelService.createModel(bpmModelParam, null);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, modelId, methodDescribe);
    }


    @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.UPDATE)
    @PostMapping("/update")
    @ApiOperation("修改模型")
    @ApiImplicitParam(name = "updateParam", value = "流程分类数据", required = true)
    public HttpResult<Object> update(@Validated @RequestBody BpmModelParam.BpmModelUpdateParam updateParam) {
        String methodDescribe = getMethodDescribe("update");
        modelService.updateModel(updateParam);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
    }


//    @PostMapping("/import")
//    @ApiOperation("导入模型")
//    @PreAuthorize("@ss.hasPermission('bpm:model:import')")
//    public CommonResult<String> importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException {
//        BpmModelCreateReqVO createReqVO = BeanUtils.toBean(importReqVO, BpmModelCreateReqVO.class);
//        // 读取文件
//        String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false);
//        return success(modelService.createModel(createReqVO, bpmnXml));
//    }


    @PostMapping("/deploy")
    @ApiOperation("部署模型")
    @Parameter(name = "id", description = "编号", required = true)
    public HttpResult<Boolean> deployModel(String id) {
        String methodDescribe = getMethodDescribe("deployModel");
        modelService.deployModel(id);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
    }

    //
//    @PutMapping("/update-state")
//    @ApiOperation("修改模型的状态", description = "实际更新的部署的流程定义的状态")
//    @PreAuthorize("@ss.hasPermission('bpm:model:update')")
//    public CommonResult<Boolean> updateModelState(@Valid @RequestBody BpmModelUpdateStateReqVO reqVO) {
//        modelService.updateModelState(reqVO.getId(), reqVO.getState());
//        return success(true);
//    }
//

    /**
     * 删除模型
     * @param id 模型编号
     */
    @GetMapping("/delete")
    @ApiOperation("删除模型")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    public HttpResult<Boolean> deleteModel(String id) {
        String methodDescribe = getMethodDescribe("deleteModel");
        modelService.deleteModel(id);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }

}
