package com.jy.flow.controller;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jy.flow.adapter.AbstractWarmFlowAdapter;
import com.jy.flow.model.dto.FlowHisTaskDto;
import com.jy.flow.model.dto.FlowTaskDto;
import com.jy.flow.model.dto.WarmFlowHandleDto;
import com.jy.flow.model.enums.FlowStatusEnum;
import com.jy.flow.model.vo.FlowTaskVo;
import com.jy.flow.service.ExecuteService;
import com.jy.framework.exception.ServiceException;
import com.jy.framework.satoken.LoginContext;
import com.jy.system.dao.SysDeptDao;
import com.jy.system.dao.SysRoleDao;
import com.jy.system.dao.SysUserDao;
import com.jy.system.model.entity.SysUser;
import jakarta.annotation.Resource;
import org.dromara.warm.flow.core.FlowFactory;
import org.dromara.warm.flow.core.dto.FlowParams;
import org.dromara.warm.flow.core.entity.HisTask;
import org.dromara.warm.flow.core.entity.Instance;
import org.dromara.warm.flow.core.entity.Node;
import org.dromara.warm.flow.core.entity.Skip;
import org.dromara.warm.flow.core.entity.Task;
import org.dromara.warm.flow.core.entity.User;
import org.dromara.warm.flow.core.enums.SkipType;
import org.dromara.warm.flow.core.enums.UserType;
import org.dromara.warm.flow.core.service.HisTaskService;
import org.dromara.warm.flow.core.service.InsService;
import org.dromara.warm.flow.core.service.NodeService;
import org.dromara.warm.flow.core.service.SkipService;
import org.dromara.warm.flow.core.service.TaskService;
import org.dromara.warm.flow.core.service.UserService;
import org.dromara.warm.flow.core.utils.StreamUtils;
import org.dromara.warm.flow.orm.entity.FlowHisTask;
import org.dromara.warm.flow.orm.entity.FlowInstance;
import org.dromara.warm.flow.orm.entity.FlowSkip;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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 java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

@RestController
@RequestMapping("/flow/execute")
public class ExecuteController {

    @Resource
    private SysUserDao sysUserDao;

    @Resource
    private SysDeptDao sysDeptDao;

    @Resource
    private SysRoleDao sysRoleDao;

    @Resource
    private HisTaskService hisTaskService;

    @Resource
    private TaskService taskService;

    @Resource
    private NodeService nodeService;

    @Resource
    private InsService insService;

    @Resource
    private UserService flowUserservice;

    @Resource
    private ExecuteService executeService;

    @Resource
    private SkipService skipService;

    /**
     * 分页待办任务列表
     */
    @GetMapping("/todoPage")
    public Page<FlowTaskVo> toDoPage(FlowTaskDto dto) {
        dto.setPermissionList(AbstractWarmFlowAdapter.permissionList());
        Page<FlowTaskVo> page = executeService.toDoPage(dto);
        List<FlowTaskVo> list = page.getRecords();
        if (list.isEmpty()) {
            return page;
        }

        List<Long> taskIds = StreamUtils.toList(list, FlowTaskVo::getId);
        List<User> userList = flowUserservice.getByAssociateds(taskIds);
        Map<Long, List<User>> map = StreamUtils.groupByKey(userList, User::getAssociated);

        HashMap<String, String> handlerMap = new HashMap<>();
        sysUserDao.list().forEach(item -> handlerMap.put(item.getId().toString(), "用户:" + item.getNickname()));
        sysRoleDao.list().forEach(item -> handlerMap.put("role:" + item.getId().toString(), "角色:" + item.getName()));
        sysDeptDao.list().forEach(item -> handlerMap.put("dept:" + item.getId().toString(), "部门:" + item.getName()));

        for (FlowTaskVo taskVo : list) {
            if (ObjectUtil.isNull(taskVo)) {
                continue;
            }

            List<User> users = map.get(taskVo.getId());
            if (ObjectUtil.isEmpty(users)) {
                continue;
            }

            StringJoiner approverJoiner = new StringJoiner("；");
            StringJoiner transferredByJoiner = new StringJoiner("；");
            StringJoiner delegateJoiner = new StringJoiner("；");

            for (User user : users) {
                String processed = handlerMap.get(user.getProcessedBy());
                switch (UserType.getByKey(user.getType())) {
                    case APPROVAL -> {
                        if (StrUtil.isNotEmpty(processed)) {
                            approverJoiner.add(processed);
                        }
                    }
                    case TRANSFER -> {
                        if (StrUtil.isNotEmpty(processed)) {
                            transferredByJoiner.add(processed);
                        }
                    }
                    case DEPUTE -> {
                        if (StrUtil.isNotEmpty(processed)) {
                            delegateJoiner.add(processed);
                        }
                    }
                }
            }

            taskVo.setApprover(approverJoiner.toString());
            taskVo.setTransferredBy(transferredByJoiner.toString());
            taskVo.setDelegate(delegateJoiner.toString());
        }
        return page;
    }

    /**
     * 分页已办任务列表
     */
    @GetMapping("/donePage")
    public Page<FlowHisTask> donePage(FlowHisTaskDto dto) {
        dto.setApprover(LoginContext.getUserId().toString());
        Page<FlowHisTask> page = executeService.donePage(dto);
        List<FlowHisTask> list = page.getRecords();
        Map<Long, String> userMap = StreamUtils.toMap(sysUserDao.list(), SysUser::getId, SysUser::getNickname);

        if (CollectionUtils.isEmpty(list)) {
            return page;
        }

        for (FlowHisTask hisTaskVo : list) {
            if (StrUtil.isNotEmpty(hisTaskVo.getCollaborator())) {
                hisTaskVo.setCollaborator(userMap.get(Long.valueOf(hisTaskVo.getCollaborator())));
            }
        }
        return page;
    }

    /**
     * 分页抄送任务列表
     */
    @GetMapping("/copyPage")
    public Page<FlowHisTask> copyPage(FlowTaskDto dto) {
        dto.setPermissionList(AbstractWarmFlowAdapter.permissionList());
        return executeService.copyPage(dto);
    }

    /**
     * 查询已办任务历史记录
     */
    @GetMapping("/doneList/{instanceId}")
    public List<HisTask> doneList(@PathVariable("instanceId") Long instanceId) {
        List<HisTask> vo = hisTaskService.list(new FlowHisTask().setInstanceId(instanceId));
        if (vo.isEmpty()) {
            return vo;
        }

        Map<Long, String> userMap = StreamUtils.toMap(sysUserDao.list(), SysUser::getId, SysUser::getNickname);
        for (HisTask hisTask : vo) {
            if (StrUtil.isNotEmpty(hisTask.getApprover())) {
                hisTask.setApprover(userMap.get(Long.valueOf(hisTask.getApprover())));
            }
            if (StrUtil.isNotEmpty(hisTask.getCollaborator())) {
                hisTask.setCollaborator(userMap.get(Long.valueOf(hisTask.getCollaborator())));
            }
        }

        return vo;
    }

    /**
     * 查询已办任务历史记录
     */
    @GetMapping("/doneListByBusinessId/{businessId}")
    public List<HisTask> doneListByBusinessId(@PathVariable("businessId") String businessId) {
        Instance instance = insService.getOne(new FlowInstance().setBusinessId(businessId));
        if (instance == null) {
            return Collections.emptyList();
        }
        return doneList(instance.getId());
    }

    /**
     * 查询跳转任意节点列表
     */
    @GetMapping("/anyNodeList/{instanceId}")
    public List<Node> anyNodeList(@PathVariable("instanceId") Long instanceId) {
        Instance instance = insService.getById(instanceId);
        return nodeService.list(FlowFactory.newNode().setDefinitionId(instance.getDefinitionId()));
    }

    /**
     * 办理流程
     */
    @PostMapping("/handle")
    public void handle(@RequestBody WarmFlowHandleDto dto) {
        Task task = taskService.getById(dto.getTaskId());
        Long definitionId = task.getDefinitionId();
        String nodeCode = null;
        FlowStatusEnum flowStatus = FlowStatusEnum.APPROVAL;

        Integer handleType = dto.getHandleType();
        String skipType = switch (handleType) {
            case 1 -> {
                Node nextNode = nodeService.getNextNode(definitionId, task.getNodeCode(), "", "PASS");
                nodeCode = nextNode.getNodeCode();
                // 如果是结束节点
                if (nextNode.getNodeType() == 2) {
                    flowStatus = FlowStatusEnum.PASS;
                }
                yield SkipType.PASS.getKey();
            }
            case 2 -> {

                nodeCode = task.getNodeCode();

                List<Skip> skipList = skipService.list(new FlowSkip().setDefinitionId(definitionId));

                List<Skip> rejectSkipList = skipList.stream()
                        .filter(item -> "REJECT".equals(item.getSkipType()))
                        .filter(item -> item.getNowNodeCode().equals(task.getNodeCode()))
                        .toList();

                int rejectSkipSize = rejectSkipList.size();
                if (rejectSkipSize == 0) {
                    while (true) {
                        String tempNodeCode = nodeCode;

                        Skip skip = skipList.stream()
                                .filter(item -> "PASS".equals(item.getSkipType()))
                                .filter(item -> item.getNextNodeCode().equals(tempNodeCode))
                                .findFirst()
                                .orElse(null);

                        if (skip == null) {
                            throw new ServiceException("流程配置错误：不存在回退节点");
                        }

                        nodeCode = skip.getNowNodeCode();

                        if (ObjectUtil.notEqual(skip.getNowNodeType(), 3)) {
                            // 回退到开始节点
                            if (skip.getNowNodeType() == 0) {
                                flowStatus = FlowStatusEnum.TOBESUBMIT;
                            }
                            break;
                        }
                    }

                } else if (rejectSkipSize == 1) {
                    Skip skip = rejectSkipList.get(0);
                    if (skip.getNextNodeType().equals(3)) {
                        throw new ServiceException("流程配置错误：节点回退到网关");
                    }
                    nodeCode = skip.getNextNodeCode();
                } else {
                    throw new ServiceException("流程配置错误：存在多个回退节点");
                }


                yield SkipType.REJECT.getKey();
            }
            case 3 -> {
                flowStatus = FlowStatusEnum.TERMINATE;
                yield null;
            }
            default -> throw new ServiceException("办理类型不存在");
        };

        FlowParams flowParams = FlowParams.build()
                .skipType(skipType)
                .handler(LoginContext.getUserId().toString())
                .nodeCode(nodeCode)
                .message(dto.getMessage())
                .permissionFlag(AbstractWarmFlowAdapter.permissionList())
                .flowStatus(flowStatus.getKeyStr());

        if (handleType == 3) {
            taskService.termination(dto.getTaskId(), flowParams);
        } else {
            taskService.skip(dto.getTaskId(), flowParams);
        }

    }

}
