package com.xfestudio.xfeservermanager.infra.http;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.time.Clock;
import java.time.Duration;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;

class IdempotencyRegistryTest {
    @Test
    void invokesAnOperationOnceAndRejectsKeyReuseWithDifferentPayload() {
        var registry = new IdempotencyRegistry(4, Duration.ofMinutes(10), Clock.systemUTC());
        var calls = new AtomicInteger();
        UUID actor = UUID.randomUUID();

        var first = registry.execute(actor, "POST", "/operations", "request-key", "body-a", () -> {
            calls.incrementAndGet();
            return CompletableFuture.completedFuture("accepted");
        });
        var replay = registry.execute(actor, "POST", "/operations", "request-key", "body-a", () -> {
            calls.incrementAndGet();
            return CompletableFuture.completedFuture("wrong");
        });

        assertThat(first.toCompletableFuture().join()).isEqualTo("accepted");
        assertThat(replay.toCompletableFuture().join()).isEqualTo("accepted");
        assertThat(calls).hasValue(1);
        assertThatThrownBy(() -> registry.execute(
                        actor,
                        "POST",
                        "/operations",
                        "request-key",
                        "body-b",
                        () -> CompletableFuture.completedFuture("wrong")))
                .isInstanceOf(IdempotencyRegistry.IdempotencyConflictException.class);
    }

    @Test
    void capacityPressureNeverEvictsAnUnexpiredCompletedResult() {
        var registry = new IdempotencyRegistry(1, Duration.ofMinutes(10), Clock.systemUTC());
        UUID actor = UUID.randomUUID();
        var calls = new AtomicInteger();
        registry.execute(actor, "POST", "/operations", "first-key", "body", () -> {
            calls.incrementAndGet();
            return CompletableFuture.completedFuture("first-result");
        }).toCompletableFuture().join();

        assertThatThrownBy(() -> registry.execute(
                        actor, "POST", "/operations", "second-key", "body",
                        () -> CompletableFuture.completedFuture("must-not-run")))
                .isInstanceOf(IdempotencyRegistry.IdempotencyCapacityException.class);

        assertThat(registry.execute(
                        actor, "POST", "/operations", "first-key", "body", () -> {
                            calls.incrementAndGet();
                            return CompletableFuture.completedFuture("duplicate");
                        }).toCompletableFuture().join())
                .isEqualTo("first-result");
        assertThat(calls).hasValue(1);
    }
}
