package com.easyagents.scheduler;

import java.time.Duration;

/**
 * 请求调度提供方持久化重试同一次逻辑触发的异常。
 *
 * <p>仅用于尚未产生业务副作用、且调用方必须保证至少一次登记的短 Handler。
 * {@code maxRefires=0} 表示不限制持久化重试次数；Provider 正常情况下应释放当前执行线程，
 * 并通过持久化的延迟触发保留原 fire 上下文。仅当 JobStore 无法写入持久重试时，
 * Provider 可按相同退避暂时占用当前线程并原地重试，以避免正常完成造成 fire 丢失。</p>
 */
public class ScheduleRefireException extends RuntimeException {

    private static final int DEFAULT_MAX_REFIRES = 0;
    private static final Duration DEFAULT_BASE_DELAY = Duration.ofMillis(250);
    private final int maxRefires;
    private final Duration baseDelay;

    public ScheduleRefireException(String message, Throwable cause) {
        this(message, cause, DEFAULT_MAX_REFIRES, DEFAULT_BASE_DELAY);
    }

    public ScheduleRefireException(String message, Throwable cause,
                                   int maxRefires, Duration baseDelay) {
        super(requireMessage(message), cause);
        if (maxRefires < 0) throw new IllegalArgumentException("maxRefires must not be negative");
        if (baseDelay == null || baseDelay.isZero() || baseDelay.isNegative()) {
            throw new IllegalArgumentException("baseDelay must be positive");
        }
        this.maxRefires = maxRefires;
        this.baseDelay = baseDelay;
    }

    /**
     * @return 最大重新执行次数，0 表示不限制
     */
    public int maxRefires() {
        return maxRefires;
    }

    public Duration delayFor(int refireNumber) {
        int shift = Math.min(4, Math.max(0, refireNumber - 1));
        return baseDelay.multipliedBy(1L << shift);
    }

    private static String requireMessage(String message) {
        if (message == null || message.isBlank()) {
            throw new IllegalArgumentException("message must not be blank");
        }
        return message;
    }
}
