package de.duehl.math.stochastic;

import org.junit.jupiter.api.Test;

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class RandomSampleWithoutPutBackTest {

    @Test
    public void emptySetFails() {
        assertThrows(IllegalArgumentException.class, () -> {
            new RandomSampleWithoutPutBack(-1, 15);
        });
    }

    @Test
    public void emptySetFails2() {
        assertThrows(IllegalArgumentException.class, () -> {
            new RandomSampleWithoutPutBack(1, 0, 15);
        });
    }

    @Test
    public void emptySetFails3() {
        assertThrows(IllegalArgumentException.class, () -> {
            new RandomSampleWithoutPutBack(18, 17, 15);
        });
    }

    @Test
    public void setWithOneMemberFailsIfSampleWantsTwoMembers() {
        assertThrows(IllegalArgumentException.class, () -> {
            new RandomSampleWithoutPutBack(1, 1, 2);
        });
    }

    @Test
    public void setWithOneMemberIsOkIfSampleWantsOneMember() {
        new RandomSampleWithoutPutBack(1, 1, 1);
    }

    @Test
    public void setWithOneMemberAndSampleWithOneMember() {
        RandomSample randomSample = new RandomSampleWithoutPutBack(1, 1, 1);
        randomSample.drawSample();
        List<Integer> actualSample = randomSample.getSample();
        assertEquals(1, actualSample.size());
        assertEquals(Integer.valueOf(1), actualSample.get(0));
    }

    @Test
    public void multiTest1() {
        int from = 1;
        int to = 100_000;
        int sampleSize = 1_000;

        List<Integer> sample = drawSample(from, to, sampleSize);
        checkSample(from, to, sampleSize, sample);
    }

    @Test
    public void multiTest2() {
        int from = 153_123;
        int to = 5_322_124;
        int sampleSize = 1_000;

        List<Integer> sample = drawSample(from, to, sampleSize);
        checkSample(from, to, sampleSize, sample);
    }

    @Test
    public void multiTest3() {
        int from = 153_123;
        int to = 5_322_124;
        int sampleSize = 13;

        List<Integer> sample = drawSample(from, to, sampleSize);
        checkSample(from, to, sampleSize, sample);
        //System.out.println(sample);
    }

    @Test
    public void multiTest4() {
        int from = 153_123;
        int to = 153_132;
        int sampleSize = 10;

        List<Integer> sample = drawSample(from, to, sampleSize);
        checkSample(from, to, sampleSize, sample);
        //System.out.println(sample);
    }

    private List<Integer> drawSample(int from, int to, int sampleSize) {
        RandomSample randomSample = new RandomSampleWithoutPutBack(from, to, sampleSize);
        randomSample.drawSample();
        List<Integer> actualSample = randomSample.getSample();
        return actualSample;
    }

    private void checkSample(int from, int to, int sampleSize, List<Integer> sample) {
        assertEquals(sampleSize, sample.size());
        for (int index = 0; index < sampleSize; ++index) {
            int sampleNumber = sample.get(index);
            assertTrue(from <= sampleNumber);
            assertTrue(sampleNumber <= to);
            for (int upperIndex = index + 1; upperIndex < sampleSize; ++upperIndex) {
                int upperSampleNumber = sample.get(upperIndex);
                assertTrue(sampleNumber != upperSampleNumber);
            }
        }
    }

    @Test
    public void sampleWithAllNumbersHasAllNumbers1to62() {
        sampleWithAllNumbersHasAllNumbers(1, 62);
    }

    @Test
    public void sampleWithAllNumbersHasAllNumbers9to864() {
        sampleWithAllNumbersHasAllNumbers(9, 864);
    }

    @Test
    public void sampleWithAllNumbersHasAllNumbers99to211() {
        sampleWithAllNumbersHasAllNumbers(99, 211);
    }

    private void sampleWithAllNumbersHasAllNumbers(int from, int to) {
        int sampleSize = to + 1 - from;

        List<Integer> sample = drawSample(from, to, sampleSize);
        Collections.sort(sample);
        for (int position = 1; position <= sampleSize; ++position) {
            int index = position - 1;
            int value = sample.get(index);
            assertEquals(index + from, value);
        }
    }

    @Test
    public void notWanted() {
        int from = 1;
        int to = 10;
        int sampleSize = 3;
        List<Integer> notWantedNumbers = new ArrayList<>();
        notWantedNumbers.add(1);
        notWantedNumbers.add(3);
        notWantedNumbers.add(5);
        notWantedNumbers.add(6);
        notWantedNumbers.add(8);
        notWantedNumbers.add(9);
        notWantedNumbers.add(10);

        RandomSample randomSample = new RandomSampleWithoutPutBack(from, to, sampleSize);
        randomSample.setIndicesToIgnore(notWantedNumbers);
        randomSample.drawSample();
        List<Integer> sample = randomSample.getSample();

        checkSample(from, to, sampleSize, sample);
        assertTrue(sample.contains(2));
        assertTrue(sample.contains(4));
        assertTrue(sample.contains(7));
    }

}
