package cn.stylefeng.workflow.instance.modular.task.taskopt.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.workflow.api.entity.instance.RuntimeNode;
import cn.stylefeng.workflow.api.entity.task.RuTask;
import cn.stylefeng.workflow.api.enums.NodeStatusEnum;
import cn.stylefeng.workflow.api.enums.TaskStatusEnum;
import cn.stylefeng.workflow.instance.modular.manage.pojo.request.RuntimeNodeRequest;
import cn.stylefeng.workflow.instance.modular.manage.service.RuntimeNodeService;
import cn.stylefeng.workflow.instance.modular.task.enums.RuTaskExceptionEnum;
import cn.stylefeng.workflow.instance.modular.task.pojo.operate.ReworkRequest;
import cn.stylefeng.workflow.instance.modular.task.service.RuTaskService;
import cn.stylefeng.workflow.instance.modular.task.service.TaskDaoWithEvent;
import cn.stylefeng.workflow.instance.modular.task.taskopt.TaskReworkService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class TaskReworkServiceImpl implements TaskReworkService {

    @Resource
    private RuntimeNodeService runtimeNodeService;

    @Resource
    private RuTaskService ruTaskService;

    @Resource
    private TaskDaoWithEvent taskDaoWithEvent;

    @Override
    public List<RuTask> getInstanceCurrentUserFinishedTask(Long instanceId) {

        RuntimeNodeRequest runtimeNodeRequest = new RuntimeNodeRequest();
        runtimeNodeRequest.setInstanceId(instanceId);
        runtimeNodeRequest.setNodeStatus(NodeStatusEnum.RUNNING.getStatus());
        List<RuntimeNode> runtimeNodeList = this.runtimeNodeService.findList(runtimeNodeRequest);
        if (ObjectUtil.isEmpty(runtimeNodeList)) {
            throw new ServiceException(RuTaskExceptionEnum.NO_RUNNING_NODE);
        }

        List<RuTask> finishedAndNotWaitingTask = new ArrayList<>();

        Long userId = LoginContext.me().getLoginUser().getUserId();
        for (RuntimeNode runtimeNode : runtimeNodeList) {
            LambdaQueryWrapper<RuTask> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(RuTask::getRuNodeId, runtimeNode.getRuNodeId());
            wrapper.eq(RuTask::getApprover, userId);
            wrapper.in(RuTask::getTaskStatus, TaskStatusEnum.PROCESSED.getCode(), TaskStatusEnum.PROCESSING.getCode(), TaskStatusEnum.WAIT_TO_START.getCode());
            List<RuTask> ruTaskList = this.ruTaskService.list(wrapper);
            if (ObjectUtil.isEmpty(ruTaskList)) {
                continue;
            }

            Set<RuTask> processedTaskList = ruTaskList.stream().filter(item -> item.getTaskStatus().equals(TaskStatusEnum.PROCESSED.getCode())).collect(Collectors.toSet());

            Set<RuTask> processingTaskList = ruTaskList.stream().filter(item -> item.getTaskStatus().equals(TaskStatusEnum.PROCESSING.getCode())).collect(Collectors.toSet());

            Set<RuTask> waitToStartTaskList = ruTaskList.stream().filter(item -> item.getTaskStatus().equals(TaskStatusEnum.WAIT_TO_START.getCode())).collect(Collectors.toSet());

            if (ObjectUtil.isEmpty(waitToStartTaskList) && ObjectUtil.isEmpty(processingTaskList) && ObjectUtil.isNotEmpty(processedTaskList)) {
                finishedAndNotWaitingTask.addAll(processedTaskList);
            }
        }

        if (ObjectUtil.isEmpty(finishedAndNotWaitingTask)) {
            throw new ServiceException(RuTaskExceptionEnum.NO_ALREADY_FINISHED_TASK);
        }

        return finishedAndNotWaitingTask;
    }

    @Override
    public void reworkTask(ReworkRequest reworkRequest) {
        List<RuTask> userHaveFinishedTaskList = this.getInstanceCurrentUserFinishedTask(reworkRequest.getInstanceId());
        for (RuTask ruTask : userHaveFinishedTaskList) {
            RuTask userNewTask = new RuTask();
            BeanUtil.copyProperties(ruTask, userNewTask);

            userNewTask.setTaskId(IdWorker.getId());

            userNewTask.setReadFlag(YesOrNotEnum.N.getCode());

            userNewTask.setSuggestContent(null);

            userNewTask.setBeginTime(new Date());

            userNewTask.setSuggestTime(null);

            userNewTask.setTaskStatus(TaskStatusEnum.PROCESSING.getCode());

            taskDaoWithEvent.saveTask(userNewTask);

            return;
        }
    }

}
