package com.lanyuanxiaoyao.leopard.core.task;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.core.repository.TaskRepository;
import com.lanyuanxiaoyao.leopard.core.service.TaskService;
import java.time.LocalDateTime;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

/**
 * 任务运行
 *
 * @author lanyuanxiaoyao
 * @version 20250924
 */
@Slf4j
public abstract class TaskRunner {
  private final ApplicationContext context;

  protected TaskRunner(ApplicationContext context) {
    this.context = context;
  }

  public abstract String process(Map<String, Object> params, StepUpdater updater) throws Exception;

  public void run(TaskService.TaskTemplate template, Map<String, Object> params) {
    var taskRepository = context.getBean(TaskRepository.class);
    var task = new Task();
    task.setName(template.name());
    task.setDescription(template.description());
    task.setStatus(Task.Status.RUNNING);
    task.setLaunchedTime(LocalDateTime.now());
    taskRepository.saveAndFlush(task);

    try {
      var result = process(params, step -> {
        synchronized (task) {
          taskRepository.updateStepById(task.getId(), step);
        }
      });

      task.setStatus(Task.Status.SUCCESS);
      task.setStep(1.0);
      task.setFinishedTime(LocalDateTime.now());
      if (StrUtil.isNotBlank(result)) {
        task.setResult(result);
      }
      taskRepository.saveAndFlush(task);
    } catch (Throwable throwable) {
      log.error("任务执行失败", throwable);
      task.setStatus(Task.Status.FAILURE);
      task.setFinishedTime(LocalDateTime.now());
      if (ObjectUtil.isNotNull(throwable)) {
        task.setError(ExceptionUtil.stacktraceToString(throwable));
      }
      taskRepository.saveAndFlush(task);
    }
  }

  public interface StepUpdater {
    void update(double step);
  }
}
