package de.accso.flexinale.common.shared_kernel;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.Set;
import java.util.stream.Stream;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

class SelectionMultiMapTest {

    private record VALUE(String s) {}

    private static Stream<Arguments> allAlgorithms() {
        return Stream.of(
            Arguments.of(Selection.SelectionAlgorithm.RANDOM),
            Arguments.of(Selection.SelectionAlgorithm.CONSTANT_FIRST),
            Arguments.of(Selection.SelectionAlgorithm.CONSTANT_LAST),
            Arguments.of(Selection.SelectionAlgorithm.ROUND_ROBIN),
            Arguments.of(Selection.SelectionAlgorithm.ALL)
        );
    }

    @ParameterizedTest
    @MethodSource("allAlgorithms")
    public void testInitialMap(Selection.SelectionAlgorithm algorithm) {
        // arrange
        SelectionMultiMap<String, VALUE> sut = new SelectionMultiMap<>(algorithm);

        // act
        Set<?> result = sut.get("notthere");

        // assert
        assertThat(result).isNull();
    }

    @ParameterizedTest
    @MethodSource("allAlgorithms")
    public void testSetAndGet(Selection.SelectionAlgorithm algorithm) {
        // arrange
        SelectionMultiMap<String, VALUE> sut = new SelectionMultiMap<>(algorithm);
        VALUE fortyTwo = new VALUE("42");

        // act
        sut.put("key", fortyTwo);

        // assert
        assertThat(sut.get("key").size()).isEqualTo(1);
        assertThat(sut.get("key").contains(fortyTwo)).isTrue();
        assertThat(sut.get("notthere")).isNull();
    }

    @ParameterizedTest
    @MethodSource("allAlgorithms")
    public void testSetDuplicatesAndGet(Selection.SelectionAlgorithm algorithm) {
        // arrange
        SelectionMultiMap<String, VALUE> sut = new SelectionMultiMap<>(algorithm);
        VALUE fortyTwo = new VALUE("42");

        // act
        sut.put("key", fortyTwo);
        sut.put("key", fortyTwo);

        // assert
        assertThat(sut.get("key").size()).isEqualTo(1);
        assertThat(sut.get("key").contains(fortyTwo)).isTrue();
        assertThat(sut.get("notthere")).isNull();
    }

    @ParameterizedTest
    @MethodSource("allAlgorithms")
    public void testSetAndGetMultipleValues(Selection.SelectionAlgorithm algorithm) {
        // arrange
        SelectionMultiMap<String, VALUE> sut = new SelectionMultiMap<>(algorithm);
        VALUE fortyTwo = new VALUE("42");
        VALUE fortyThree = new VALUE("43");
        VALUE fortyFour = new VALUE("44");

        // act
        sut.put("key", fortyTwo);
        sut.put("key", fortyThree);
        sut.put("key", fortyFour);

        // assert
        assertThat(sut.get("key").size()).isEqualTo(3);
        assertThat(sut.get("key").contains(fortyTwo)).isTrue();
        assertThat(sut.get("key").contains(fortyThree)).isTrue();
        assertThat(sut.get("key").contains(fortyFour)).isTrue();
        assertThat(sut.get("notthere")).isNull();
    }
}