package com.easyagents.scheduler;

import org.junit.Test;

import java.time.ZoneId;
import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

/**
 * {@link ScheduleDefinition} 不可变性和输入边界测试。
 */
public class ScheduleDefinitionTest {

    /**
     * 验证任务参数会被防御复制。
     */
    @Test
    public void shouldDefensivelyCopyParameters() {
        Map<String, String> parameters = new HashMap<>();
        parameters.put("reportId", "r-1");

        ScheduleDefinition definition = definition(parameters);
        parameters.put("reportId", "r-2");

        assertEquals("r-1", definition.parameters().get("reportId"));
        assertThrows(
            UnsupportedOperationException.class,
            () -> definition.parameters().put("new", "value")
        );
    }

    /**
     * 验证超大参数会被拒绝。
     */
    @Test
    public void shouldRejectOversizedParameters() {
        Map<String, String> parameters = Map.of(
            "payload",
            "x".repeat(ScheduleDefinition.MAX_PARAMETER_BYTES)
        );

        ScheduleException exception = assertThrows(
            ScheduleException.class,
            () -> definition(parameters)
        );
        assertEquals(ScheduleErrorCode.INVALID_DEFINITION, exception.errorCode());
    }

    /**
     * 验证 Cron 表达式会规范化空白并拒绝超过 JDBC 表上限的内容。
     */
    @Test
    public void shouldNormalizeAndBoundCronExpression() {
        CronSchedulePlan normalized = new CronSchedulePlan(
            "0   0/5  * * * ?",
            ZoneId.of("UTC")
        );
        assertEquals("0 0/5 * * * ?", normalized.expression());

        assertThrows(
            IllegalArgumentException.class,
            () -> new CronSchedulePlan("0".repeat(121), ZoneId.of("UTC"))
        );
    }

    private ScheduleDefinition definition(Map<String, String> parameters) {
        return new ScheduleDefinition(
            new ScheduleId("reports", "daily"),
            "generate-report",
            new CronSchedulePlan("0 0 2 * * ?", ZoneId.of("Asia/Shanghai")),
            MisfirePolicy.FIRE_ONCE_NOW,
            ConcurrencyPolicy.DISALLOW,
            true,
            parameters,
            "daily report"
        );
    }
}
