package com.njcn.bpm.controller;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.bpm.pojo.param.BpmProcessDefinitionInfoParam;
import com.njcn.bpm.pojo.po.BpmCategory;
import com.njcn.bpm.pojo.po.BpmForm;
import com.njcn.bpm.pojo.po.BpmProcessDefinitionInfo;
import com.njcn.bpm.pojo.vo.BpmProcessDefinitionInfoVO;
import com.njcn.bpm.service.IBpmCategoryService;
import com.njcn.bpm.service.IBpmFormService;
import com.njcn.bpm.service.IBpmProcessDefinitionService;
import com.njcn.bpm.strategy.BpmTaskCandidateStartUserSelectStrategy;
import com.njcn.bpm.utils.BpmProcessDefinitionConvert;
import com.njcn.common.pojo.annotation.OperateInfo;
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.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.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

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


/**
 * @author hongawen
 */
@RestController
@RequestMapping("/bpm/processDefinition")
@Validated
@Slf4j
@Api(tags = "管理后台 - 流程定义")
@RequiredArgsConstructor
public class BpmProcessDefinitionController extends BaseController {

    private final IBpmProcessDefinitionService processDefinitionService;

    private final IBpmFormService formService;

    private final IBpmCategoryService categoryService;

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/page")
    @ApiOperation("获得流程定义分页")
    @ApiImplicitParam(name = "bpmProcessDefinitionInfoQueryParam", value = "查询参数", required = true)
    public HttpResult<Page<BpmProcessDefinitionInfoVO>> getProcessDefinitionPage(
            BpmProcessDefinitionInfoParam.BpmProcessDefinitionInfoQueryParam bpmProcessDefinitionInfoQueryParam) {
        String methodDescribe = getMethodDescribe("getProcessDefinitionPage");
        Page<ProcessDefinition> pageResult = processDefinitionService.getProcessDefinitionPage(bpmProcessDefinitionInfoQueryParam);
        if (CollUtil.isEmpty(pageResult.getRecords())) {
            Page<BpmProcessDefinitionInfoVO> result = new Page<>();
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
        }
        // 获得 Category Map
        Map<String, BpmCategory> categoryMap = categoryService.getCategoryMap(
                convertSet(pageResult.getRecords(), ProcessDefinition::getCategory));
        // 获得 Deployment Map
        Map<String, Deployment> deploymentMap = processDefinitionService.getDeploymentMap(
                convertSet(pageResult.getRecords(), ProcessDefinition::getDeploymentId));
        // 获得 BpmProcessDefinitionInfoDO Map
        Map<String, BpmProcessDefinitionInfo> processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap(
                convertSet(pageResult.getRecords(), ProcessDefinition::getId));
        // 获得 Form Map
        Map<String, BpmForm> formMap = formService.getFormMap(
                convertSet(processDefinitionMap.values(), BpmProcessDefinitionInfo::getFormId));

        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionPage(
                pageResult, deploymentMap, processDefinitionMap, formMap, categoryMap), methodDescribe);
    }

    /**
     * 获得流程定义列表
     * @param suspensionState 挂起状态
     */
    @GetMapping("/list")
    @ApiOperation("获得流程定义列表")
    @Parameter(name = "suspensionState", description = "挂起状态", required = true) // 参见 Flowable SuspensionState 枚举
    public HttpResult<List<BpmProcessDefinitionInfoVO>> getProcessDefinitionList(Integer suspensionState) {
        String methodDescribe = getMethodDescribe("getProcessDefinitionList");
        List<ProcessDefinition> list = processDefinitionService.getProcessDefinitionListBySuspensionState(suspensionState);
        if (CollUtil.isEmpty(list)) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, new ArrayList<>(), methodDescribe);
        }

        // 获得 BpmProcessDefinitionInfoDO Map
        Map<String, BpmProcessDefinitionInfo> processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap(
                convertSet(list, ProcessDefinition::getId));

        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionList(
                list, null, processDefinitionMap, null, null), methodDescribe);
    }

    @GetMapping("/get")
    @ApiOperation("获得流程定义")
    @Parameter(name = "id", description = "流程编号", required = true, example = "1024")
    @Parameter(name = "key", description = "流程定义标识", required = true, example = "1024")
    public HttpResult<BpmProcessDefinitionInfoVO> getProcessDefinition(
            @RequestParam(value = "id", required = false) String id,
            @RequestParam(value = "key", required = false) String key) {
        String methodDescribe = getMethodDescribe("getProcessDefinition");
        ProcessDefinition processDefinition = id != null ? processDefinitionService.getProcessDefinition(id)
                : processDefinitionService.getActiveProcessDefinition(key);
        if (processDefinition == null) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
        }
        BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId());
        List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinition(
                processDefinition, null, null, null, null, bpmnModel, userTaskList), methodDescribe);
    }

}
