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.BpmProcessInstanceCreateReqDTO;
import com.njcn.bpm.pojo.dto.PageResult;
import com.njcn.bpm.pojo.param.instance.BpmProcessInstanceCancelParam;
import com.njcn.bpm.pojo.param.instance.BpmProcessInstancePageParam;
import com.njcn.bpm.pojo.po.BpmCategory;
import com.njcn.bpm.pojo.po.BpmProcessDefinitionInfo;
import com.njcn.bpm.pojo.vo.instance.BpmProcessInstanceVO;
import com.njcn.bpm.service.IBpmCategoryService;
import com.njcn.bpm.service.IBpmProcessDefinitionService;
import com.njcn.bpm.service.task.IBpmProcessInstanceService;
import com.njcn.bpm.service.task.IBpmTaskService;
import com.njcn.bpm.utils.BpmProcessInstanceConvert;
import com.njcn.bpm.utils.BpmnModelUtils;
import com.njcn.bpm.utils.CollectionUtils;
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.supervision.api.BusinessCommonFeignClient;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.po.Dept;
import com.njcn.user.pojo.vo.UserVO;
import com.njcn.web.controller.BaseController;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.utils.RequestUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;

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


/**
 * @author hongawen
 */
@RestController
@RequestMapping("/bpm/processInstance")
@Validated
@Slf4j
@Api(tags = "管理后台 - 流程实例")
@RequiredArgsConstructor
public class BpmProcessInstanceController extends BaseController {

    @Resource
    private IBpmProcessInstanceService processInstanceService;
    @Resource
    private  BusinessCommonFeignClient businessCommonFeignClient;
    @Resource
    private IBpmTaskService taskService;
    @Resource
    private IBpmProcessDefinitionService processDefinitionService;
    @Resource
    private IBpmCategoryService categoryService;

    @Resource
    private UserFeignClient userFeignClient;
    @Resource
    private DeptFeignClient deptFeignClient;

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/myPage")
    @ApiOperation("获得我的实例分页列表")
    public HttpResult<Page<BpmProcessInstanceVO>> getProcessInstanceMyPage(@Validated  @RequestBody BpmProcessInstancePageParam bpmProcessInstancePageParam) {
        String methodDescribe = getMethodDescribe("getProcessInstanceMyPage");
        PageResult<HistoricProcessInstance> pageResult = processInstanceService.getProcessInstancePage(RequestUtil.getUserIndex(), bpmProcessInstancePageParam);
        if (CollUtil.isEmpty(pageResult.getList())) {
            Page<BpmProcessInstanceVO> result = new Page<>();
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
        }

        // 拼接返回
        Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(
                convertList(pageResult.getList(), HistoricProcessInstance::getId));
        Map<String, ProcessDefinition> processDefinitionMap = processDefinitionService.getProcessDefinitionMap(
                convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId));
        Map<String, BpmCategory> categoryMap = categoryService.getCategoryMap(
                convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory));
        PageResult<BpmProcessInstanceVO> bpmProcessInstanceVOPageResult = BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult, processDefinitionMap, categoryMap, taskMap, null, null,businessCommonFeignClient);
        //封装调整为当前系统的格式
        Page<BpmProcessInstanceVO> page = new Page<>();
        page.setRecords(bpmProcessInstanceVOPageResult.getList());
        page.setTotal(bpmProcessInstanceVOPageResult.getTotal());
        page.setSize(PageFactory.getPageSize(bpmProcessInstancePageParam));
        page.setCurrent(PageFactory.getPageNum(bpmProcessInstancePageParam));
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, page, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/managerPage")
    @ApiOperation("获得管理流程实例的分页列表")
    public HttpResult<Page<BpmProcessInstanceVO>> getProcessInstanceManagerPage(@Validated  @RequestBody BpmProcessInstancePageParam bpmProcessInstancePageParam) {
        String methodDescribe = getMethodDescribe("getProcessInstanceManagerPage");
        PageResult<HistoricProcessInstance> pageResult = processInstanceService.getProcessInstancePage(
                null, bpmProcessInstancePageParam);
        if (CollUtil.isEmpty(pageResult.getList())) {
            Page<BpmProcessInstanceVO> result = new Page<>();
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
        }
        // 拼接返回
        Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(
                convertList(pageResult.getList(), HistoricProcessInstance::getId));
        Map<String, ProcessDefinition> processDefinitionMap = processDefinitionService.getProcessDefinitionMap(
                convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId));
        Map<String, BpmCategory> categoryMap = categoryService.getCategoryMap(
                convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory));

        // 发起人信息
        List<UserVO> userList = userFeignClient.getUserVOByIdList(convertList(pageResult.getList(), HistoricProcessInstance::getStartUserId)).getData();
        Map<String, UserVO> userMap = CollectionUtils.convertMap(userList, UserVO::getId);

        List<Dept> deptList = deptFeignClient.getDeptInfoListByIds(convertList(userMap.values(), UserVO::getDeptId)).getData();
        Map<String, Dept> deptMap = CollectionUtils.convertMap(deptList, Dept::getId);

        PageResult<BpmProcessInstanceVO> bpmProcessInstanceVOPageResult = BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult,
                processDefinitionMap, categoryMap, taskMap, userMap, deptMap,businessCommonFeignClient);
        //封装调整为当前系统的格式
        Page<BpmProcessInstanceVO> page = new Page<>();
        page.setRecords(bpmProcessInstanceVOPageResult.getList());
        page.setTotal(bpmProcessInstanceVOPageResult.getTotal());
        page.setSize(PageFactory.getPageSize(bpmProcessInstancePageParam));
        page.setCurrent(PageFactory.getPageNum(bpmProcessInstancePageParam));
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, page, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/create")
    @ApiOperation("新建流程实例")
    public HttpResult<String> createProcessInstance(@Validated @RequestBody BpmProcessInstanceCreateReqDTO bpmProcessInstanceCreateReqDTO) {
        String methodDescribe = getMethodDescribe("createProcessInstance");
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, processInstanceService.createProcessInstance(RequestUtil.getUserIndex(), bpmProcessInstanceCreateReqDTO), methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @GetMapping("/get")
    @ApiOperation("获得指定流程实例")
    public HttpResult<BpmProcessInstanceVO> getProcessInstance(String id) {
        String methodDescribe = getMethodDescribe("getProcessInstance");
        HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(id);
        if (processInstance == null) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
        }
        // 拼接返回
        ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(
                processInstance.getProcessDefinitionId());
        BpmProcessDefinitionInfo processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(
                processInstance.getProcessDefinitionId());
        String bpmnXml = BpmnModelUtils.getBpmnXml(
                processDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId()));
        UserVO startUser = userFeignClient.getUserById(processInstance.getStartUserId()).getData();
        Dept dept = null;
        if (startUser != null) {
            dept = deptFeignClient.getDeptById(startUser.getDeptId()).getData();
        }
        BpmProcessInstanceVO bpmProcessInstanceVO = BpmProcessInstanceConvert.INSTANCE.buildProcessInstance(processInstance,
                processDefinition, processDefinitionInfo, bpmnXml, startUser, dept);
        return  HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, bpmProcessInstanceVO, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/cancelByStartUser")
    @ApiOperation("用户取消流程实例")
    public HttpResult<Boolean> cancelProcessInstanceByStartUser(@Valid @RequestBody BpmProcessInstanceCancelParam cancelReqVO) {
        String methodDescribe = getMethodDescribe("cancelProcessInstanceByStartUser");
        processInstanceService.cancelProcessInstanceByStartUser(RequestUtil.getUserIndex(), cancelReqVO);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/cancelByAdmin")
    @ApiOperation("管理员取消流程实例")
    public HttpResult<Boolean> cancelProcessInstanceByManager(
            @Valid @RequestBody BpmProcessInstanceCancelParam cancelReqVO) {
        String methodDescribe = getMethodDescribe("cancelProcessInstanceByManager");
        processInstanceService.cancelProcessInstanceByAdmin(RequestUtil.getUserIndex(), cancelReqVO);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.ADD)
    @ApiOperation("创建流程实例")
    @PostMapping("/createProcessInstance")
    HttpResult<String> createProcessInstance(@RequestParam("userId") String userId, @RequestBody BpmProcessInstanceCreateReqDTO reqDTO){
        String methodDescribe = getMethodDescribe("createProcessInstance");
        String instanceId =  processInstanceService.createProcessInstance(userId, reqDTO);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, instanceId, methodDescribe);
    }


    @ApiOperation(value = "删除流程实例(会删除已经审核的流程慎用)")
    @GetMapping(value = "/deleteInstance")
    public HttpResult<Boolean> delete(@ApiParam(value = "流程实例ID", required = true) @RequestParam String instanceIds) {
        String methodDescribe = getMethodDescribe("delete");
        processInstanceService.delete(instanceIds,"测试删除");
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);

    }

}
