package com.cameleer.server.core.ingestion;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

class WriteBufferTest {

    private WriteBuffer<String> buffer;

    @BeforeEach
    void setUp() {
        buffer = new WriteBuffer<>(10);
    }

    @Test
    void offerSucceedsUntilCapacity() {
        for (int i = 0; i < 10; i++) {
            assertTrue(buffer.offer("item-" + i), "offer should succeed for item " + i);
        }
        assertEquals(10, buffer.size());
    }

    @Test
    void offerReturnsFalseWhenFull() {
        for (int i = 0; i < 10; i++) {
            buffer.offer("item-" + i);
        }
        assertFalse(buffer.offer("overflow"), "offer should return false when buffer is full");
    }

    @Test
    void offerBatchSucceedsWhenCapacitySufficient() {
        List<String> batch = List.of("a", "b", "c");
        assertTrue(buffer.offerBatch(batch));
        assertEquals(3, buffer.size());
    }

    @Test
    void offerBatchReturnsFalseWithoutPartialInsertWhenOverflow() {
        for (int i = 0; i < 8; i++) {
            buffer.offer("item-" + i);
        }
        // Buffer has 2 remaining, batch of 3 should fail entirely
        List<String> batch = List.of("a", "b", "c");
        assertFalse(buffer.offerBatch(batch));
        assertEquals(8, buffer.size(), "no items should have been added on failed batch");
    }

    @Test
    void drainReturnsItemsAndRemovesThem() {
        buffer.offer("a");
        buffer.offer("b");
        buffer.offer("c");

        List<String> drained = buffer.drain(2);
        assertEquals(2, drained.size());
        assertEquals(1, buffer.size());
    }

    @Test
    void drainWithEmptyQueueReturnsEmptyList() {
        List<String> drained = buffer.drain(5);
        assertTrue(drained.isEmpty());
    }

    @Test
    void isFullReturnsTrueAtCapacity() {
        assertFalse(buffer.isFull());
        for (int i = 0; i < 10; i++) {
            buffer.offer("item-" + i);
        }
        assertTrue(buffer.isFull());
    }

    @Test
    void sizeTracksCurrentDepth() {
        assertEquals(0, buffer.size());
        buffer.offer("a");
        assertEquals(1, buffer.size());
        buffer.drain(1);
        assertEquals(0, buffer.size());
    }

    @Test
    void capacityReturnsConfiguredCapacity() {
        assertEquals(10, buffer.capacity());
    }

    @Test
    void remainingCapacityDecreasesWithOffers() {
        assertEquals(10, buffer.remainingCapacity());
        buffer.offer("a");
        assertEquals(9, buffer.remainingCapacity());
    }
}
