package p.packer.services;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import p.packer.messages.PackerProjectContext;

import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

final class PackerProjectWriteCoordinatorTest {
    @TempDir
    Path tempDir;

    private final PackerProjectWriteCoordinator coordinator = new PackerProjectWriteCoordinator();

    @AfterEach
    void cleanup() {
        coordinator.close();
    }

    @Test
    void serializesSameProjectWritesInSubmissionOrder() throws Exception {
        final PackerProjectContext project = new PackerProjectContext("main", tempDir.resolve("main"));
        final List<String> trace = new CopyOnWriteArrayList<>();
        final CountDownLatch firstStarted = new CountDownLatch(1);

        final Future<String> first = coordinator.submit(project, () -> {
            trace.add("first-start");
            firstStarted.countDown();
            Thread.sleep(100L);
            trace.add("first-end");
            return "first";
        });

        assertTrue(firstStarted.await(2, TimeUnit.SECONDS));
        final Future<String> second = coordinator.submit(project, () -> {
            trace.add("second");
            return "second";
        });

        assertEquals("first", first.get(2, TimeUnit.SECONDS));
        assertEquals("second", second.get(2, TimeUnit.SECONDS));
        assertEquals(List.of("first-start", "first-end", "second"), trace);
    }
}
