package com.aizuda.snailjob.server.retry.task.support.generator.task;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.aizuda.snailjob.common.core.enums.RetryTaskStatusEnum;
import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
import com.aizuda.snailjob.server.common.util.DateUtils;
import com.aizuda.snailjob.server.retry.task.dto.RetryTaskGeneratorDTO;
import com.aizuda.snailjob.server.retry.task.support.RetryTaskConverter;
import com.aizuda.snailjob.server.retry.task.support.timer.RetryTimerContext;
import com.aizuda.snailjob.server.retry.task.support.timer.RetryTimerTask;
import com.aizuda.snailjob.server.retry.task.support.timer.RetryTimerWheel;
import com.aizuda.snailjob.template.datasource.persistence.mapper.RetryTaskMapper;
import com.aizuda.snailjob.template.datasource.persistence.po.RetryTask;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Objects;

/**
 * <p>
 *
 * </p>
 *
 * @author opensnail
 * @date 2025-01-26
 */
@Component
@RequiredArgsConstructor
public class RetryTaskGeneratorHandler {
    private final RetryTaskMapper retryTaskMapper;

    /**
     * 生成重试任务
     *
     * @param generator RetryTaskGeneratorContext
     */
    public void generateRetryTask(RetryTaskGeneratorDTO generator) {

        RetryTask retryTask = RetryTaskConverter.INSTANCE.toRetryTask(generator);
        Integer taskStatus = generator.getTaskStatus();
        if (Objects.isNull(taskStatus)) {
            taskStatus = RetryTaskStatusEnum.WAITING.getStatus();
        }
        retryTask.setTaskStatus(taskStatus);
        retryTask.setOperationReason(generator.getOperationReason());

        retryTask.setExtAttrs(StrUtil.EMPTY);
        Assert.isTrue(1 == retryTaskMapper.insert(retryTask), () -> new SnailJobServerException("插入重试任务失败"));

        if (!RetryTaskStatusEnum.WAITING.getStatus().equals(taskStatus)) {
            return;
        }

        // 放到到时间轮
        long delay = generator.getNextTriggerAt() - DateUtils.toNowMilli();
        RetryTimerContext timerContext = RetryTaskConverter.INSTANCE.toRetryTimerContext(generator);
        timerContext.setRetryTaskId(retryTask.getId());
        RetryTimerWheel.registerWithRetry(() -> new RetryTimerTask(timerContext), Duration.ofMillis(delay));
    }
}
