package cn.axzo.workflow.server.controller.web.bpmn;

import cn.axzo.workflow.client.feign.bpmn.ProcessDefinitionApi;
import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO;
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO;
import cn.axzo.workflow.common.model.response.BpmPageResult;
import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO;
import cn.axzo.workflow.core.service.BpmnProcessDefinitionService;
import cn.axzo.workflow.core.service.BpmnProcessModelService;
import cn.axzo.workflow.core.service.converter.BpmnProcessDefinitionConverter;
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Map;

import static cn.axzo.workflow.common.constant.MetaInfoConstants.MODEL_DESCRIPTION;
import static cn.azxo.framework.common.model.CommonResponse.success;

/**
 * 流程定义相关控制器
 */
@Slf4j
@RequestMapping({"/web/v1/api/process/definition", "/api/process/definition"})
@RestController
@ErrorReporter
@Validated
public class BpmnProcessDefinitionController implements ProcessDefinitionApi {
    @Resource
    private BpmnProcessDefinitionService bpmnProcessDefinitionService;
    @Resource
    private BpmnProcessDefinitionConverter processDefinitionConverter;
    @Resource
    private BpmnProcessModelService bpmnProcessModelService;


    /**
     * 获取活跃的流程定义分页
     */
    @Operation(summary = "获取活跃的流程定义分页")
    @GetMapping("/page")
    @Override
    public CommonResponse<BpmPageResult<BpmnProcessDefinitionVO>> getProcessDefinitionPage(@Validated @RequestBody BpmnProcessDefinitionPageDTO dto) {
        log.info("获取活跃的流程定义分页getProcessDefinitionPage===>>>参数：{}", JSONUtil.toJsonStr(dto));
        return success(bpmnProcessDefinitionService.getProcessDefinitionPage(dto));
    }

    /**
     * 通过模型 ID 更新流程定义
     *
     * @param dto
     * @return
     */
    @Operation(summary = "通过模型 ID 更新流程定义")
    @PutMapping("/update")
    @Override
    public CommonResponse<Boolean> updateProcessDefinition(@Validated @RequestBody BpmnProcessDefinitionUpdateDTO dto) {
        bpmnProcessDefinitionService.updateProcessDefinition(dto);
        return success(true);
    }

    /**
     * 获得编号对应的 ProcessDefinition
     *
     * @param processDefinitionId 定义编号
     * @return 流程定义
     */
    @Operation(summary = "获得编号对应的流程定义")
    @GetMapping("/get")
    @Override
    public CommonResponse<BpmnProcessDefinitionVO> getProcessDefinition(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId) {
        log.info("获取活跃的流程定义分页getProcessDefinition===>>>参数：{}", JSONUtil.toJsonStr(processDefinitionId));
        return success(bpmnProcessDefinitionService.getProcessDefinition(processDefinitionId));
    }


    /**
     * 获得 deploymentId 对应的 ProcessDefinition
     *
     * @param deploymentId 部署编号
     * @return 流程定义
     */
    @Operation(summary = "获得部署 ID 对应的流程定义")
    @GetMapping("/getByDeploymentId")
    @Override
    public CommonResponse<BpmnProcessDefinitionVO> getProcessDefinitionByDeploymentId(
            @NotBlank(message = "流程部署 ID 不能为空") @RequestParam String deploymentId) {
        log.info(" 获得 deploymentId 对应的 getProcessDefinitionByDeploymentId===>>>参数：{}", JSONUtil.toJsonStr(deploymentId));
        ProcessDefinition result = bpmnProcessDefinitionService.getProcessDefinitionByDeploymentId(deploymentId);
        return success(processDefinitionConverter.toVo(result));
    }


    /**
     * 获得流程定义标识对应的激活的流程定义
     *
     * @param key 流程定义的标识
     * @return 流程定义
     */
    @Operation(summary = "获得流程定义标识对应的激活的流程定义")
    @GetMapping("/active/getByKey")
    @Override
    public CommonResponse<BpmnProcessDefinitionVO> getActiveProcessDefinitionByKey(@NotBlank(message =
            "模型定义KEY" +
                    "不能为空") @RequestParam String key) {
        log.info("获得流程定义标识对应的激活的流程定义 getActiveProcessDefinitionByKey===>>>参数：{}", JSONUtil.toJsonStr(key));
        return success(bpmnProcessDefinitionService.getActiveProcessDefinitionByKey(key, key));
    }

    /**
     * 获取指定流程定义是否有激活状态的数据
     *
     * @param deploymentId
     * @return
     */
    @Operation(summary = "获取指定流程定义是否有激活状态的数据")
    public CommonResponse<Boolean> hasActiveProcessDefinition(String deploymentId) {
        log.info("获得流程定义标识对应的激活的流程定义 getActiveProcessDefinitionByKey===>>>参数：{}", JSONUtil.toJsonStr(deploymentId));
        return success(bpmnProcessDefinitionService.hasActiveProcessDefinition(deploymentId));
    }

    /**
     * 挂起/激活流程，
     * 激活：SuspensionState.ACTIVE.getStateCode()
     * 挂起：SuspensionState.SUSPENDED.getStateCode()
     * {@link SuspensionState}
     *
     * @param processDefinitionId 流程定义 ID
     * @param state 状态
     */
    @Operation(summary = "挂起/激活流程")
    @PutMapping("/state/update")
    @Override
    public CommonResponse<Boolean> getActiveProcessDefinitionByKey(@NotBlank(message = "流程定义ID不能为空") @RequestParam String processDefinitionId,
                                                                   @NotNull(message = "状态不能为空") @RequestParam Integer state) {
        log.info("挂起/激活流程 updateProcessDefinitionSuspendedState===>>>参数：{},{}", processDefinitionId, state);
        bpmnProcessDefinitionService.updateProcessDefinitionSuspendedState(processDefinitionId, state);
        return success(true);
    }


    /**
     * 获取指定模型的定义 ID
     *
     * @param tenantId 租户 ID
     * @param category 业务分类
     * @return 流程定义ID
     */
    @Operation(summary = "获取指定模型的定义 ID")
    @GetMapping("/active/getByCategory")
    @Override
    public CommonResponse<String> getActiveProcessDefinitionId(@RequestParam(required = false) String tenantId,
                                                               @NotBlank(message = "分类不能为空") @RequestParam(required =
                                                                       false) String category) {
        log.info("挂起/激活流程 getActiveProcessDefinitionId===>>>参数：{},{}", tenantId, category);
        String result = bpmnProcessDefinitionService.getActiveProcessDefinitionId(tenantId, category);
        return success(result);
    }

    /**
     * 获取指定模型激活的流程定义 JSON 模型
     *
     * @param modelId 模型 ID
     * @param tenantId 租户 ID
     * @param category 业务分类
     * @return
     */
    @Operation(summary = "获取指定模型激活的流程定义 JSON 模型")
    @GetMapping("/active/json/model")
    @Override
    public CommonResponse<BpmnModelUpdateDTO> getActiveProcessDefinitionJsonModel(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId,
                                                                                  @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category,
                                                                                  @RequestParam(required = false) String tenantId) {
        String finalTenantId = StringUtils.hasText(tenantId) ? tenantId : "";
        BpmnModelDetailVO modelDetail = bpmnProcessModelService.getById(modelId, finalTenantId);
        String activeProcessDefinitionId = bpmnProcessDefinitionService.getActiveProcessDefinitionId(finalTenantId,
                category);

        BpmnProcessDefinitionVO processDefinition =
                bpmnProcessDefinitionService.getProcessDefinition(activeProcessDefinitionId);

        BpmnModelUpdateDTO updateDTO = new BpmnModelUpdateDTO();
        updateDTO.setProcessModelId(modelDetail.getId());
        updateDTO.setKey(modelDetail.getKey());
        updateDTO.setName(modelDetail.getName());
        updateDTO.setCategory(modelDetail.getCategory());
        updateDTO.setTenantId(modelDetail.getTenantId());
        updateDTO.setJsonModel(processDefinition.getJsonModel());

        Map<String, String> metaInfoMap = JSON.parseObject(modelDetail.getMetaInfo(), Map.class);
        updateDTO.setDescription(metaInfoMap.get(MODEL_DESCRIPTION));
        return success(updateDTO);
    }

    @Operation(summary = "删除指定流程部署")
    @GetMapping("/delete")
    @Override
    public CommonResponse<Void> delete(String deploymentId, Boolean cascade) {
        bpmnProcessDefinitionService.delete(deploymentId, cascade);
        return success();
    }
}
