package com.njcn.bpm.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.bpm.enums.BpmTaskStatusEnum;
import com.njcn.bpm.pojo.dto.PageResult;
import com.njcn.bpm.pojo.param.task.*;
import com.njcn.bpm.pojo.po.BpmCategory;
import com.njcn.bpm.pojo.po.BpmForm;
import com.njcn.bpm.pojo.vo.TodoVO;
import com.njcn.bpm.pojo.vo.instance.BpmProcessInstanceVO;
import com.njcn.bpm.pojo.vo.task.BpmTaskVO;
import com.njcn.bpm.service.IBpmCategoryService;
import com.njcn.bpm.service.IBpmFormService;
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.BpmTaskConvert;
import com.njcn.bpm.utils.CollectionUtils;
import com.njcn.bpm.utils.TodoVOConvert;
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.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.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.bpmn.model.UserTask;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.flowable.task.api.history.HistoricTaskInstance;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

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


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

    @Resource
    private IBpmTaskService taskService;

    @Resource
    private BusinessCommonFeignClient businessCommonFeignClient;

    @Resource
    private IBpmProcessInstanceService processInstanceService;

    @Resource
    private IBpmFormService formService;

    @Resource
    private UserFeignClient userFeignClient;

    @Resource
    private DeptFeignClient deptFeignClient;

    @Resource
    private IBpmProcessDefinitionService processDefinitionService;

    @Resource
    private IBpmCategoryService categoryService;


    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/todoList")
    @ApiOperation("获取待办任务分页")
    public HttpResult<Page<BpmTaskVO>> getTaskTodoPage(@Validated @RequestBody BpmTaskParam.BpmTaskQueryParam bpmTaskQueryParam) {
        String methodDescribe = getMethodDescribe("getTaskTodoPage");
        PageResult<Task> pageResult = taskService.getTaskTodoPage(RequestUtil.getUserIndex(), bpmTaskQueryParam);
        if (CollUtil.isEmpty(pageResult.getList())) {
            Page<BpmTaskVO> result = new Page<>();
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
        }
        // 拼接数据
        Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap(
                convertSet(pageResult.getList(), Task::getProcessInstanceId));
        List<UserVO> userList = userFeignClient.getUserVOByIdList(convertList(processInstanceMap.values(), ProcessInstance::getStartUserId)).getData();
        Map<String, UserVO> userMap = CollectionUtils.convertMap(userList, UserVO::getId);
        PageResult<BpmTaskVO> bpmTaskVOPageResult = BpmTaskConvert.INSTANCE.buildTodoTaskPage(pageResult, processInstanceMap, userMap,businessCommonFeignClient);
        //封装调整为当前系统的格式
        Page<BpmTaskVO> page = new Page<>();
        page.setRecords(bpmTaskVOPageResult.getList());
        page.setTotal(bpmTaskVOPageResult.getTotal());
        page.setSize(PageFactory.getPageSize(bpmTaskQueryParam));
        page.setCurrent(PageFactory.getPageNum(bpmTaskQueryParam));
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, page, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/todoAllList")
    @ApiOperation("获取所有待办任务")
    public HttpResult<List<BpmTaskVO>> todoAllList() {
        String methodDescribe = getMethodDescribe("todoAllList");
        List<Task> pageResult = taskService.todoAllList(RequestUtil.getUserIndex());
        if (CollUtil.isEmpty(pageResult)) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, new ArrayList<>(), methodDescribe);
        }
        // 拼接数据
        Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap(
                convertSet(pageResult, Task::getProcessInstanceId));
        List<UserVO> userList = userFeignClient.getUserVOByIdList(convertList(processInstanceMap.values(), ProcessInstance::getStartUserId)).getData();
        Map<String, UserVO> userMap = CollectionUtils.convertMap(userList, UserVO::getId);
        List<BpmTaskVO> bpmTaskVOPageResult = BpmTaskConvert.INSTANCE.buildTodoTaskList(pageResult, processInstanceMap, userMap,businessCommonFeignClient);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, bpmTaskVOPageResult, methodDescribe);
    }


    /**
     * 获取全部待办任务
     * 1. 待办工作流程
     * 2. 审核不通过的流程，需重新编辑并发起
     * 3. 预告警事件待办
     * 4. 终端周期到期待检测
     * 5. todo... 可能电能质量问题后续也要想办法搜集进来
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/allTodoList")
    @ApiOperation("获取全部待办任务")
    @ApiImplicitParam(name = "bpmTaskQueryParam", value = "查询参数", required = true)
    public HttpResult<List<TodoVO>> allTodoList() {
        String methodDescribe = getMethodDescribe("allTodoList");
        List<TodoVO> result = new ArrayList<>();
        // 获取当前用户所有不通过的工作流程
        List<BpmProcessInstanceVO> rejectProcessInstanceList = getRejectProcessInstanceList();
        if(CollectionUtil.isNotEmpty(rejectProcessInstanceList)){
            // 转为统一的todoVO3
            result.addAll(TodoVOConvert.convertByBpmProcessInstance(rejectProcessInstanceList));
        }
        // 获取当前用户所有待办工作流程
        HttpResult<List<BpmTaskVO>> todoAllList = this.todoAllList();
        if(CollectionUtil.isNotEmpty(todoAllList.getData())){
            // 转为统一的todoVO3
            result.addAll(TodoVOConvert.convertByBpmTaskVO(todoAllList.getData()));
        }
        // 获取没有流程的一些待办信息
        result.addAll(businessCommonFeignClient.getTodoBusiness().getData());
        result = result.stream().sorted(Comparator.comparing(TodoVO::getTaskCreateTime).reversed()).collect(Collectors.toList());
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
    }



    /**
     * 获取当前用户所有的不通过流程
     */
    private List<BpmProcessInstanceVO> getRejectProcessInstanceList() {
        // 先获取当前用户所有审核不通过的流程实例ID
        Set<String> instanceIdSet = businessCommonFeignClient.getAllRejectInstanceId().getData();
        if(CollUtil.isEmpty(instanceIdSet)){
            return new ArrayList<>();
        }
        List<HistoricProcessInstance> instances = processInstanceService.getRejectProcessInstanceList(RequestUtil.getUserIndex(),instanceIdSet);
        if (CollUtil.isEmpty(instances)) {
           return new ArrayList<>();
        }
        // 拼接返回
        Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(
                convertList(instances, HistoricProcessInstance::getId));
        Map<String, ProcessDefinition> processDefinitionMap = processDefinitionService.getProcessDefinitionMap(
                convertSet(instances, HistoricProcessInstance::getProcessDefinitionId));
        Map<String, BpmCategory> categoryMap = categoryService.getCategoryMap(
                convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory));
        return BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(instances, processDefinitionMap, categoryMap, taskMap, null, null,businessCommonFeignClient);
    }


    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/doneList")
    @ApiOperation("获取已办任务分页")
    @ApiImplicitParam(name = "bpmTaskQueryParam", value = "查询参数", required = true)
    public HttpResult<Page<BpmTaskVO>> getTaskDonePage(@Validated @RequestBody BpmTaskParam.BpmTaskQueryParam bpmTaskQueryParam) {
        String methodDescribe = getMethodDescribe("getTaskDonePage");
        PageResult<HistoricTaskInstance> pageResult = taskService.getTaskDonePage(RequestUtil.getUserIndex(), bpmTaskQueryParam);
        if (CollUtil.isEmpty(pageResult.getList())) {
            Page<BpmTaskVO> result = new Page<>();
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
        }
        // 拼接数据
        Map<String, HistoricProcessInstance> processInstanceMap = processInstanceService.getHistoricProcessInstanceMap(
                convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId));
        List<UserVO> userList = userFeignClient.getUserVOByIdList(convertList(processInstanceMap.values(), HistoricProcessInstance::getStartUserId)).getData();
        Map<String, UserVO> userMap = CollectionUtils.convertMap(userList, UserVO::getId);
        PageResult<BpmTaskVO> bpmTaskRespVOPageResult = BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, null,businessCommonFeignClient);
        //封装调整为当前系统的格式
        Page<BpmTaskVO> page = new Page<>();
        page.setRecords(bpmTaskRespVOPageResult.getList());
        page.setTotal(bpmTaskRespVOPageResult.getTotal());
        page.setSize(PageFactory.getPageSize(bpmTaskQueryParam));
        page.setCurrent(PageFactory.getPageNum(bpmTaskQueryParam));

        List<BpmTaskVO> records = page.getRecords();
        for (BpmTaskVO record : records) {
            if(record.getStatus().equals(BpmTaskStatusEnum.CANCEL.getStatus()) && record.getReason().equals("系统自动取消")){
                record.setStatus(BpmTaskStatusEnum.APPROVE.getStatus());
                record.setReason(BpmTaskStatusEnum.APPROVE.getName());
                // 找到由谁完成的
                HttpResult<List<BpmTaskVO>> taskListByProcessInstanceId = this.getTaskListByProcessInstanceId(record.getProcessInstanceId());
                if(CollectionUtil.isNotEmpty(taskListByProcessInstanceId.getData())){
                    for (BpmTaskVO datum : taskListByProcessInstanceId.getData()) {
                        if(datum.getStatus().equals(BpmTaskStatusEnum.APPROVE.getStatus()) && datum.getTaskDefinitionKey().equals(record.getTaskDefinitionKey())){
                            record.setReason("由".concat(datum.getAssigneeUser().getName()).concat("完成审批"));
                        }
                    }
                }
            }
        }

        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, page, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/AllList")
    @ApiOperation("获取全部任务的分页")
    @ApiImplicitParam(name = "bpmTaskQueryParam", value = "查询参数", required = true)
    public HttpResult<Page<BpmTaskVO>> getTaskManagerPage(@Validated @RequestBody BpmTaskParam.BpmTaskQueryParam bpmTaskQueryParam) {
        String methodDescribe = getMethodDescribe("getTaskManagerPage");
        PageResult<HistoricTaskInstance> pageResult = taskService.getTaskPage(RequestUtil.getUserIndex(), bpmTaskQueryParam);
        if (CollUtil.isEmpty(pageResult.getList())) {
            Page<BpmTaskVO> result = new Page<>();
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
        }

        // 拼接数据
        Map<String, HistoricProcessInstance> processInstanceMap = processInstanceService.getHistoricProcessInstanceMap(
                convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId));
        // 获得 User 和 Dept Map
        List<String> userIds = convertList(processInstanceMap.values(), HistoricProcessInstance::getStartUserId);
        userIds.addAll(convertSet(pageResult.getList(), TaskInfo::getAssignee));

        List<UserVO> userList = userFeignClient.getUserVOByIdList(userIds).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<BpmTaskVO> bpmTaskVOPageResult = BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, deptMap,businessCommonFeignClient);

        //封装调整为当前系统的格式
        Page<BpmTaskVO> page = new Page<>();
        page.setRecords(bpmTaskVOPageResult.getList());
        page.setTotal(bpmTaskVOPageResult.getTotal());
        page.setSize(PageFactory.getPageSize(bpmTaskQueryParam));
        page.setCurrent(PageFactory.getPageNum(bpmTaskQueryParam));
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, page, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @GetMapping("/listByProcessInstanceId")
    @ApiOperation("获得指定流程实例的任务列表")
    @ApiImplicitParam(name = "processInstanceId", value = "查询参数", required = true)
    public HttpResult<List<BpmTaskVO>> getTaskListByProcessInstanceId(String processInstanceId) {
        String methodDescribe = getMethodDescribe("getTaskListByProcessInstanceId");
        List<HistoricTaskInstance> taskList = taskService.getTaskListByProcessInstanceId(processInstanceId);
        if (CollUtil.isEmpty(taskList)) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
        }

        // 拼接数据
        HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
        // 获得 User 和 Dept Map
        List<String> userIds = convertListByFlatMap(taskList, task -> Stream.of(task.getAssignee(), task.getOwner()));
        userIds.add(processInstance.getStartUserId());
        List<UserVO> userList = userFeignClient.getUserVOByIdList(userIds).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);
        // 获得 Form Map
        Map<String, BpmForm> formMap = formService.getFormMap(convertSet(taskList, TaskInfo::getFormKey));

        List<BpmTaskVO> bpmTaskRespVOS = BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance,
                formMap, userMap, deptMap);

        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, bpmTaskRespVOS, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/approve")
    @ApiOperation("通过任务")
    @ApiImplicitParam(name = "bpmTaskApproveParam", value = "查询参数", required = true)
    public HttpResult<Boolean> approveTask(@Validated @RequestBody BpmTaskApproveParam bpmTaskApproveParam) {
        String methodDescribe = getMethodDescribe("approveTask");
        taskService.approveTask(RequestUtil.getUserIndex(), bpmTaskApproveParam);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }


    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/reject")
    @ApiOperation("不通过任务")
    @ApiImplicitParam(name = "bpmTaskRejectParam", value = "查询参数", required = true)
    public HttpResult<Boolean> rejectTask(@Validated @RequestBody BpmTaskRejectParam bpmTaskRejectParam) {
        String methodDescribe = getMethodDescribe("rejectTask");
        taskService.rejectTask(RequestUtil.getUserIndex(), bpmTaskRejectParam);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @GetMapping("/listByReturn")
    @ApiOperation("获取所有可回退的节点")
    @ApiImplicitParam(name = "taskId", value = "查询参数", required = true)
    public HttpResult<List<BpmTaskVO>> getTaskListByReturn(@RequestParam("id") String id) {
        String methodDescribe = getMethodDescribe("getTaskListByReturn");
        List<UserTask> userTaskList = taskService.getUserTaskListByReturn(id);
        List<BpmTaskVO> taskList = userTaskList.stream().map(userTask -> {
            BpmTaskVO bpmTaskVO = new BpmTaskVO();
            bpmTaskVO.setName(userTask.getName());
            bpmTaskVO.setTaskDefinitionKey(userTask.getId());
            return bpmTaskVO;
        }).collect(Collectors.toList());
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, taskList, methodDescribe);
    }


    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/return")
    @ApiOperation("回退任务")
    @ApiImplicitParam(name = "bpmTaskReturnParam", value = "查询参数", required = true)
    public HttpResult<Boolean> returnTask(@Validated @RequestBody BpmTaskReturnParam bpmTaskReturnParam) {
        String methodDescribe = getMethodDescribe("returnTask");
        taskService.returnTask(RequestUtil.getUserIndex(), bpmTaskReturnParam);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }


    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/delegate")
    @ApiOperation("委派任务")
    @ApiImplicitParam(name = "reqVO", value = "查询参数", required = true)
    public HttpResult<Boolean> delegateTask(@Validated @RequestBody BpmTaskDelegateParam reqVO) {
        String methodDescribe = getMethodDescribe("delegateTask");
        taskService.delegateTask(RequestUtil.getUserIndex(), reqVO);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/transfer")
    @ApiOperation("转派任务")
    @ApiImplicitParam(name = "reqVO", value = "查询参数", required = true)
    public HttpResult<Boolean> transferTask(@Validated @RequestBody BpmTaskTransferParam reqVO) {
        String methodDescribe = getMethodDescribe("transferTask");
        taskService.transferTask(RequestUtil.getUserIndex(), reqVO);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/createSign")
    @ApiOperation("加签")
    @ApiImplicitParam(name = "reqVO", value = "查询参数", required = true)
    public HttpResult<Boolean> createSignTask(@Validated @RequestBody BpmTaskSignCreateParam reqVO) {
        String methodDescribe = getMethodDescribe("createSignTask");
        taskService.createSignTask(RequestUtil.getUserIndex(), reqVO);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/deleteSign")
    @ApiOperation("减签")
    @ApiImplicitParam(name = "reqVO", value = "查询参数", required = true)
    public HttpResult<Boolean> deleteSignTask(@Validated @RequestBody BpmTaskSignDeleteParam reqVO) {
        String methodDescribe = getMethodDescribe("createSignTask");
        taskService.deleteSignTask(RequestUtil.getUserIndex(), reqVO);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @GetMapping("/listByParentTaskId")
    @ApiOperation("获得指定父级任务的子任务列表")
    @ApiImplicitParam(name = "parentTaskId", value = "查询参数", required = true)
    public HttpResult<List<BpmTaskVO>> getTaskListByParentTaskId(String parentTaskId) {
        String methodDescribe = getMethodDescribe("getTaskListByParentTaskId");
        List<Task> taskList = taskService.getTaskListByParentTaskId(parentTaskId);
        if (CollUtil.isEmpty(taskList)) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, new ArrayList<>(), methodDescribe);
        }
        List<String> userIds = convertListByFlatMap(taskList, user -> Stream.of(user.getAssignee(),user.getOwner()));
        userIds = userIds.stream().distinct().collect(Collectors.toList());
        List<UserVO> userList = userFeignClient.getUserVOByIdList(userIds).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);
        List<BpmTaskVO> bpmTaskVOS = BpmTaskConvert.INSTANCE.buildTaskListByParentTaskId(taskList, userMap, deptMap);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, bpmTaskVOS, methodDescribe);
    }

}
