package com.easyagents.scheduler.quartz;

/**
 * 使用外部 DataSource 创建 Quartz JDBC 调度器的不可变配置。
 *
 * @param schedulerName 集群内保持一致的 Scheduler Name
 * @param instanceId 当前实例标识，通常使用 AUTO
 * @param tablePrefix Quartz 表前缀，可包含 Schema 前缀
 * @param driverDelegateClass Quartz JDBC DriverDelegate 类名
 * @param clustered 是否启用 JDBC 集群
 * @param threadCount Quartz Worker 线程数
 * @param threadPriority Quartz Worker 线程优先级
 * @param batchTriggerAcquisitionMaxCount 单次批量获取 Trigger 的最大数量
 * @param batchTriggerAcquisitionFireAheadTimeWindowMillis 可提前纳入批量的时间窗口，单位毫秒
 * @param clusterCheckinIntervalMillis 集群心跳间隔，单位毫秒
 * @param misfireThresholdMillis Misfire 判定阈值，单位毫秒
 * @param waitForJobsToCompleteOnShutdown 关闭时是否等待运行中任务完成
 * @param shutdownWaitTimeoutMillis 关闭等待运行中任务的最长时间，单位毫秒
 * @param validateSchema 启动前是否执行只读表结构校验
 */
public record QuartzSchedulerConfig(
    String schedulerName,
    String instanceId,
    String tablePrefix,
    String driverDelegateClass,
    boolean clustered,
    int threadCount,
    int threadPriority,
    int batchTriggerAcquisitionMaxCount,
    long batchTriggerAcquisitionFireAheadTimeWindowMillis,
    long clusterCheckinIntervalMillis,
    long misfireThresholdMillis,
    boolean waitForJobsToCompleteOnShutdown,
    long shutdownWaitTimeoutMillis,
    boolean validateSchema
) {

    /** Quartz 官方通用 JDBC Delegate。 */
    public static final String STANDARD_JDBC_DELEGATE =
        "org.quartz.impl.jdbcjobstore.StdJDBCDelegate";

    /**
     * 校验并创建 Quartz 配置。
     *
     * @throws IllegalArgumentException 任一配置越界时抛出
     */
    public QuartzSchedulerConfig {
        schedulerName = requireText(schedulerName, "schedulerName", 120);
        instanceId = requireText(instanceId, "instanceId", 190);
        tablePrefix = requireText(tablePrefix, "tablePrefix", 180);
        driverDelegateClass = requireText(
            driverDelegateClass,
            "driverDelegateClass",
            250
        );
        if (threadCount < 1 || threadCount > 1000) {
            throw new IllegalArgumentException("threadCount must be between 1 and 1000");
        }
        if (threadPriority < Thread.MIN_PRIORITY || threadPriority > Thread.MAX_PRIORITY) {
            throw new IllegalArgumentException("threadPriority must be between 1 and 10");
        }
        if (batchTriggerAcquisitionMaxCount < 1
                || batchTriggerAcquisitionMaxCount > threadCount) {
            throw new IllegalArgumentException(
                "batchTriggerAcquisitionMaxCount must be between 1 and threadCount"
            );
        }
        if (batchTriggerAcquisitionFireAheadTimeWindowMillis < 0
                || batchTriggerAcquisitionFireAheadTimeWindowMillis > 60_000L) {
            throw new IllegalArgumentException(
                "batchTriggerAcquisitionFireAheadTimeWindowMillis must be between 0 and 60000"
            );
        }
        if (clusterCheckinIntervalMillis < 1000) {
            throw new IllegalArgumentException(
                "clusterCheckinIntervalMillis must be at least 1000"
            );
        }
        if (misfireThresholdMillis < 1) {
            throw new IllegalArgumentException("misfireThresholdMillis must be positive");
        }
        if (shutdownWaitTimeoutMillis < 1 || shutdownWaitTimeoutMillis > 600_000L) {
            throw new IllegalArgumentException(
                "shutdownWaitTimeoutMillis must be between 1 and 600000"
            );
        }
    }

    /**
     * 创建适合常规 JDBC 集群的安全默认配置。
     *
     * @param schedulerName Scheduler Name
     * @return 默认配置
     */
    public static QuartzSchedulerConfig clusteredDefaults(String schedulerName) {
        return new QuartzSchedulerConfig(
            schedulerName,
            "AUTO",
            "QRTZ_",
            STANDARD_JDBC_DELEGATE,
            true,
            8,
            Thread.NORM_PRIORITY,
            1,
            0L,
            15_000L,
            60_000L,
            true,
            30_000L,
            true
        );
    }

    /**
     * 规范化必填配置文本。
     *
     * @param value 原始值
     * @param field 字段名
     * @param maxLength 最大长度
     * @return 规范化值
     */
    private static String requireText(String value, String field, int maxLength) {
        if (value == null || value.isBlank()) {
            throw new IllegalArgumentException(field + " must not be blank");
        }
        String normalized = value.trim();
        if (normalized.length() > maxLength) {
            throw new IllegalArgumentException(field + " length must not exceed " + maxLength);
        }
        return normalized;
    }
}
