package com.hys.app.service.system.task.impl;

import com.hys.app.framework.exception.ServiceException;
import com.hys.app.model.system.dos.TaskDO;
import com.hys.app.model.system.enums.TaskStatusEnum;
import com.hys.app.service.system.TaskManager;
import com.hys.app.service.system.task.AsyncExecutor;
import com.hys.app.service.system.task.TaskExecutor;
import com.hys.app.service.system.task.TaskRunnable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 异步任务执行器
 *
 * @author 张崧
 * @since 2023-05-12
 */
@Service
public class TaskExecutorImpl implements TaskExecutor {

    @Autowired
    private TaskManager taskManager;

    @Autowired
    private AsyncExecutor asyncExecutor;

    private final Map<String, Thread> threadMap = new ConcurrentHashMap<>();

    @Override
    public void execute(TaskDO task, TaskRunnable function, boolean checkRunning) {
        if (checkRunning && taskManager.countByRunning(task) > 0) {
            throw new ServiceException("存在未完成的任务，请等待任务完成后再执行");
        }

        // 创建任务
        task.setStatus(TaskStatusEnum.Running);
        taskManager.save(task);

        // 异步执行
        asyncExecutor.execute(thread -> onTaskStart(task.getId(), thread),
                function,
                () -> onTaskSuccess(task.getId()),
                (throwable, errorMsg) -> onTaskError(task.getId(), errorMsg));
    }

    @Override
    public void stop(Long taskId) {
        TaskDO task = taskManager.getById(taskId);
        if (task == null) {
            throw new ServiceException("任务不存在");
        }
        if (task.getStatus() != TaskStatusEnum.Running) {
            throw new ServiceException("任务非进行中状态，不能进行终止操作");
        }

        // 终止任务对应的线程
        Thread thread = threadMap.get(task.getThreadId());
        if (thread != null) {
            thread.stop();
        }
        taskManager.updateStatus(taskId, TaskStatusEnum.Stop, "手动终止");
    }

    private void onTaskStart(Long taskId, Thread thread) {
        String threadId = String.valueOf(thread.getId());
        threadMap.put(threadId, thread);

        taskManager.updateThreadId(taskId, threadId);
    }

    private void onTaskError(Long taskId, String errorMsg) {
        taskManager.updateStatus(taskId, TaskStatusEnum.Error, errorMsg);
    }

    private void onTaskSuccess(Long taskId) {
        taskManager.updateStatus(taskId, TaskStatusEnum.Success, "执行成功");
    }
}
