package com.easyagents.scheduler.quartz;

import com.easyagents.scheduler.ConcurrencyPolicy;
import com.easyagents.scheduler.MisfirePolicy;
import com.easyagents.scheduler.OnceSchedulePlan;
import com.easyagents.scheduler.ScheduleDefinition;
import com.easyagents.scheduler.ScheduleErrorCode;
import com.easyagents.scheduler.ScheduleException;
import com.easyagents.scheduler.ScheduleId;
import org.junit.Test;
import org.quartz.JobDataMap;

import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Base64;
import java.util.Map;

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

/**
 * {@link QuartzScheduleMapper} 持久字段严格性测试。
 */
public class QuartzScheduleMapperTest {

    /**
     * 验证立即触发数据保留 Misfire 监听所需的调度标识。
     */
    @Test
    public void shouldCarryScheduleIdentityForImmediateTrigger() {
        ScheduleId scheduleId = new ScheduleId("mapper", "immediate");
        JobDataMap data = QuartzScheduleMapper.immediateData(
            scheduleId,
            "invocation",
            Map.of("key", "value")
        );

        assertEquals(scheduleId, QuartzScheduleMapper.toScheduleId(data));
    }

    /**
     * 验证损坏的恢复布尔值不会静默解释为 false。
     */
    @Test
    public void shouldRejectCorruptedBooleanValue() {
        JobDataMap data = QuartzScheduleMapper.toJobDetail(definition()).getJobDataMap();
        data.put(QuartzScheduleMapper.KEY_RECOVER, "corrupted");

        ScheduleException exception = assertThrows(
            ScheduleException.class,
            () -> QuartzScheduleMapper.toDefinition(data)
        );
        assertEquals(ScheduleErrorCode.PROVIDER_FAILURE, exception.errorCode());
    }

    /**
     * 验证持久参数损坏会归类为 Provider 数据错误。
     */
    @Test
    public void shouldClassifyCorruptedPersistedParametersAsProviderFailure() {
        JobDataMap data = QuartzScheduleMapper.toJobDetail(definition()).getJobDataMap();
        String encodedKey = Base64.getUrlEncoder().withoutPadding().encodeToString(
            "payload".getBytes(StandardCharsets.UTF_8)
        );
        data.put(
            QuartzScheduleMapper.PARAMETER_PREFIX + encodedKey,
            "x".repeat(ScheduleDefinition.MAX_PARAMETER_BYTES)
        );

        ScheduleException exception = assertThrows(
            ScheduleException.class,
            () -> QuartzScheduleMapper.toDefinition(data)
        );
        assertEquals(ScheduleErrorCode.PROVIDER_FAILURE, exception.errorCode());
    }

    /**
     * 创建映射测试定义。
     *
     * @return 测试定义
     */
    private static ScheduleDefinition definition() {
        return new ScheduleDefinition(
            new ScheduleId("mapper", "strict"),
            "handler",
            new OnceSchedulePlan(Instant.parse("2099-01-01T00:00:00Z")),
            MisfirePolicy.FIRE_ONCE_NOW,
            ConcurrencyPolicy.DISALLOW,
            true,
            Map.of(),
            "strict mapper"
        );
    }
}
