package com.ho.flow.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.PageInfo;
import com.ho.common.tools.annotation.LogAnnotation;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.constant.ContextConstant;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.entity.OrderDept;
import com.ho.common.tools.entity.SimpleUser;
import com.ho.common.tools.exception.BaseResponseCode;
import com.ho.common.tools.exception.BusinessException;
import com.ho.common.tools.exception.DataResult;
import com.ho.common.tools.service.RedisService;
import com.ho.common.tools.util.PageResult;
import com.ho.common.tools.util.PageUtils;
import com.ho.flow.constant.WorkOrderConstant;
import com.ho.flow.entity.WorkOrder;
import com.ho.flow.service.ProcessFlowService;
import com.ho.flow.service.WorkOrderPictureService;
import com.ho.flow.service.WorkOrderService;
import com.ho.flow.vo.req.workorder.*;
import com.ho.flow.vo.resp.workorder.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author fancl
 * @desc: 工作流Controller
 * @date 2023/2/5
 */
@RequestMapping(ContextConstant.FLOW_CONTEXT + "processFlow")
@RestController
@Api(tags = "工单工作流")
public class ProcessFlowController {

    @Autowired
    ProcessFlowService processFlowService;

    @Autowired
    WorkOrderService workOrderService;

    @Autowired
    WorkOrderPictureService pictureService;

    @Autowired
    RedisService redisService;

    //执行工单的岗位
    @Value("#{'${flow.workOrder.doing}'.split(',')}")
    String[] doing;

    //验收工单的岗位
    @Value("#{'${flow.workOrder.check}'.split(',')}")
    String[] check;

    //评价工单的岗位
    @Value("#{'${flow.workOrder.appraise}'.split(',')}")
    String[] appraise;

    @PostMapping("preDo")
    @ApiOperation(value = "流转前的方法")
    public DataResult<PreDoResp> preDo(@RequestBody @Valid TaskUserReq taskUserReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        String userTokenKey = RedisKeyConstant.User.TOKEN + token;
        List<Integer> depts = new ArrayList<>();
        Integer groupId = null;
        //根据用户的登陆方式(账号还是手机号),延长对应缓存
        if (redisService.hasKey(userTokenKey)) {
            SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
            depts = simpleUser.getDepts();
            groupId = simpleUser.getGroupId();
        }
        taskUserReq.setTenantId(String.valueOf(groupId));
        //查当前任务,并根据任务查询对应岗位列表
        Task task = processFlowService.getTaskById(taskUserReq);
        //取到
        String taskKeyName = task.getTaskDefinitionKey();
        //根据岗位查询可分配人员
        List<String> postCodes = new ArrayList<>();
        if (WorkOrderConstant.TaskNodeName.node1.equals(taskKeyName)) {
            postCodes = Arrays.asList(doing);
        } else if (WorkOrderConstant.TaskNodeName.node2.equals(taskKeyName)) {
            postCodes = Arrays.asList(check);
        } else if (WorkOrderConstant.TaskNodeName.node3.equals(taskKeyName)) {
            postCodes = Arrays.asList(appraise);
        }
        PreDoResp preDoResp = new PreDoResp();
        //查可选人员列表
        List<OrderDept> orderDeptUsers = workOrderService.selectOrderUser(groupId, postCodes);
        preDoResp.setOrderDeptUsers(orderDeptUsers);
        //查下一节点任务名
        String nextTaskName = processFlowService.getNextTaskName(taskUserReq.getProcessInstId());
        preDoResp.setNextTaskName(nextTaskName);
        //查询对应任务详情
        Task taskById = processFlowService.getTaskById(taskUserReq);
        if (taskById != null) {
            WorkOrderRespVO workOrderRespVO = workOrderService.findByProcInstId(taskById.getProcessInstanceId());
            if (workOrderRespVO != null) {
                preDoResp.setTitle(workOrderRespVO.getTitle());
            }
        }
        return DataResult.success(preDoResp);
    }

    /**
     * 只有工单发起人可以保存工单
     * 其他人只能处理工单
     *
     * @param addReq
     * @param request
     * @return
     */
    @PostMapping("saveOrder")
    @ApiOperation(value = "保存工单")
    @LogAnnotation(title = "工单工作流", action = "保存工单")
    public DataResult<String> saveOrder(@RequestBody @Valid WorkOrderAddReqVO addReq, HttpServletRequest request) {

        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //因为可以多次保存
        //所以判断工单是否已经创建,没创建就创建,已经创建就修改
        //只在新建时发起流程,修改不需要再次发起流程
        Long id = addReq.getId();
        if (id == null) {
            //新增工单和图片信息,并发起流程
            //设置groupId
            addReq.setGroupId(simpleUser.getGroupId());
            //设置发起人
            addReq.setUserId(simpleUser.getUserId());
            String processInstanceId = processFlowService.saveOrderAndStartProcess(addReq);
            return DataResult.success(processInstanceId);
        } else {
            //只修改表单信息
            WorkOrderRespVO one = workOrderService.getOne(id);
            if (one == null) {
                throw new BusinessException(BaseResponseCode.WORK_ORDER_NOT_EXISTS);
            }
            //修改工单表单,调用修改方法
            //更新图片
            WorkOrderUpdateReqVO workOrderUpdateReq = new WorkOrderUpdateReqVO();
            BeanUtil.copyProperties(addReq, workOrderUpdateReq);
            workOrderService.updateWorkOrder(workOrderUpdateReq);
            return DataResult.success(one.getProcessId());
        }

    }

    @PostMapping("claimTask")
    @ApiOperation(value = "接收任务")
    @LogAnnotation(title = "工单工作流", action = "接收任务")
    public DataResult claimTask(@RequestBody @Valid TaskUserReq taskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //设置租户id
        taskReq.setTenantId(String.valueOf(simpleUser.getGroupId()));
        taskReq.setUserId(simpleUser.getUserId());
        processFlowService.doClaimTask(taskReq);
        //代办应该分页,做个java内存分页处理
        return DataResult.success();
    }

    @PostMapping("queryTodoList")
    @ApiOperation(value = "查询代办列表")
    public DataResult<List<TaskDone>> queryTodoList(@RequestBody(required = false) @Valid DoListTaskReq doListTaskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        Map<String, List<Task>> taskMap = processFlowService.getTodoList(simpleUser);
        List<TaskDone> todoList = new ArrayList<>();
        //代办不分页,转换为TaskDone对象
        if (!taskMap.isEmpty()) {
            todoList = processFlowService.getToDoListFromTask(taskMap, doListTaskReq);
        }
        if (!todoList.isEmpty()) {
            //根据优先级排序然后根据时间
            todoList = todoList.stream().sorted(
                    Comparator.comparing(TaskDone::getPriority, Comparator.nullsLast(String::compareTo)).reversed().
                            thenComparing(TaskDone::getStartTime, Comparator.nullsLast(Date::compareTo)).reversed()
            ).collect(Collectors.toList());
        }
        return DataResult.success(todoList);
    }

    @PostMapping("queryDoneList")
    @ApiOperation(value = "查询已办列表")
    public DataResult<PageResult<TaskDone>> queryDoneList(@RequestBody @Valid DoListTaskReq doListTaskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        List<HistoricTaskInstance> taskList = processFlowService.getDoneList(simpleUser);
        List<TaskDone> doneList = new ArrayList<>();

        if (!taskList.isEmpty()) {
            doneList = processFlowService.getDoneListFromTask(taskList, doListTaskReq);
        }
        doneList = doneList.stream().collect(Collectors.toMap(TaskDone::getProcessInstanceId, a -> a, (s1, s2) -> {
            //如果两个任务标题相同,比较时间,选择时间大的
            long difference = DateUtil.betweenMs(s1.getStartTime(), s2.getStartTime());
            if (difference > 0) {
                return s2;
            } else {
                return s1;
            }
        })).values().stream().sorted(
                //根据时间倒序排序
                Comparator.comparing(TaskDone::getStartTime).reversed()
        ).collect(Collectors.toList());
        PageResult pageResult = new PageResult<>();
        if (!doneList.isEmpty()) {
            //获取到代办任务
            DataResult<List<TaskDone>> listDataResult = queryTodoList(doListTaskReq, request);
            //代办的任务
            List<TaskDone> todoList = listDataResult.getData();
            Map<String, List<TaskDone>> todoMap = todoList.stream().collect(Collectors.groupingBy(TaskDone::getProcessInstanceId));
            //移除在代办任务中存在的任务对象
            doneList.removeIf(s -> {
                boolean flag = false;
                if (todoMap.get(s.getProcessInstanceId()) != null) {
                    flag = true;
                }
                return flag;
            });
        }
        if (!doneList.isEmpty()) {
            List list = PageUtils.dealList(doneList, doListTaskReq.getPageNum(), doListTaskReq.getPageSize());
            pageResult = PageUtils.getPageResult(new PageInfo<>(list));
            pageResult.setTotalRows(doneList.size());
            pageResult.setTotalPages(doneList.size() / doListTaskReq.getPageSize() + 1);
        }
        return DataResult.success(pageResult);
    }


    @PostMapping("doTask")
    @ApiOperation(value = "完成任务,即流转任务")
    @LogAnnotation(title = "工单工作流", action = "流转任务")
    public DataResult doTask(@RequestBody @Valid DoTaskReq doTaskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //设置租户id
        doTaskReq.setTenantId(String.valueOf(simpleUser.getGroupId()));
        //设置发送者的id
        doTaskReq.setSenderId(simpleUser.getUserId());
        //完成任务的责任人必须和自己相同,否则需要给出提示
        doTaskReq.setAssigneeUser(simpleUser.getUserId());
        processFlowService.doCompleteTask(doTaskReq);
        return DataResult.success();
    }

    @PostMapping("nullify")
    @ApiOperation(value = "流程作废")
    @LogAnnotation(title = "工单工作流", action = "流程作废")
    public DataResult nullifyTask(@RequestBody DoTaskReq doTaskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //设置租户id
        doTaskReq.setTenantId(String.valueOf(simpleUser.getGroupId()));
        //完成任务的责任人必须和自己相同,否则需要给出提示
        doTaskReq.setAssigneeUser(simpleUser.getUserId());
        WorkOrderRespVO vo = workOrderService.selectByProcessInstId(doTaskReq.getProcessInstId());
        if (vo != null) {
            WorkOrder workOrder = new WorkOrder();
            BeanUtils.copyProperties(vo, workOrder);
            workOrder.setDeleted(CommonConstant.DELETED_FLAG);
            workOrderService.update(workOrder);
        }
        processFlowService.doNullifyTaskTask(doTaskReq);
        return DataResult.success();
    }


    @PostMapping("rejectTask")
    @ApiOperation(value = "退回任务")
    @LogAnnotation(title = "工单工作流", action = "退回任务")
    public DataResult rejectTask(@RequestBody RejectTaskReq rejectTaskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //设置发送人
        rejectTaskReq.setUserId(simpleUser.getUserId());
        //设置租户id
        rejectTaskReq.setTenantId(String.valueOf(simpleUser.getGroupId()));
        processFlowService.doRejectTask(rejectTaskReq);
        return DataResult.success();
    }

    @PostMapping("discardTask")
    @ApiOperation(value = "作废任务")
    @LogAnnotation(title = "工单工作流", action = "作废任务")
    public DataResult discardTask(@RequestBody TaskReq taskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //设置租户id
        taskReq.setTenantId(String.valueOf(simpleUser.getGroupId()));
        processFlowService.doDiscardTask(taskReq);
        return DataResult.success();
    }

    @PostMapping("fallBackTask")
    @ApiOperation(value = "回退任务列表")
    public DataResult<List<FallBackTaskResp>> fallBackTask(@RequestBody FallBackTaskReq fallBackTaskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //设置租户id
        fallBackTaskReq.setTenantId(String.valueOf(simpleUser.getGroupId()));
        List<FallBackTaskResp> fallBackTaskResps = processFlowService.getFallBackTask(fallBackTaskReq);
        return DataResult.success(fallBackTaskResps);
    }

    @PostMapping("circulationTask")
    @ApiOperation(value = "流转记录")
    public DataResult<List<HisTaskResp>> circulationTask(@RequestBody CirculationTaskReq taskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //设置租户id
        taskReq.setTenantId(String.valueOf(simpleUser.getGroupId()));
        List<HisTaskResp> hisTaskRespList = processFlowService.getCirculationTask(taskReq);
        return DataResult.success(hisTaskRespList);
    }

    @PostMapping("workOrderDetails")
    @ApiOperation(value = "工单详情")
    public DataResult<WorkOrderRespVO> workOrderDetails(@RequestBody TaskReq taskReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        //根据流程id获取工单业务对象
        WorkOrderRespVO vo = workOrderService.selectByProcessInstId(taskReq.getProcessInstId());

        TaskUserReq taskUserReq = new TaskUserReq();
        taskUserReq.setTenantId(String.valueOf(simpleUser.getGroupId()));
        taskUserReq.setProcessInstId(taskReq.getProcessInstId());
        //根据流程实例查询任务对象taskUserReq
        Task task = processFlowService.getTaskById(taskUserReq);
        if (task != null) {
            //设置当前步骤节点
            vo.setCurrentStep(task.getTaskDefinitionKey());
            //有执行人就设置haveAssignee为true
            if (task.getAssignee() != null) {
                vo.setHaveAssignee(true);
            } else {
                vo.setHaveAssignee(false);
            }
        } else if (CommonConstant.DELETED_FLAG.equals(vo.getDeleted())) {
            //设置当前步骤节点
            vo.setCurrentStep(WorkOrderConstant.TaskNodeName.deleted);
        } else {
            vo.setCurrentStep(WorkOrderConstant.TaskNodeName.end);
        }
        //查询工单业务相关的图片信息
        List<PictureRespVO> pictureRespVOS = pictureService.selectByOrderId(vo.getId());
        vo.setPictureResps(pictureRespVOS);
        return DataResult.success(vo);
    }
}
