package net.ranides.assira.collection.query;

import net.ranides.test.CQueryAssert;
import org.junit.Assert;
import org.junit.Test;

import net.ranides.assira.collection.iterators.EnumerationUtils;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;

public class CQueryBuilderTest {

    @Test
    public void fromEmpty() {
        CQueryAssert.assertEquals(Collections.emptyList(), CQuery.from().empty());
    }

    @Test
    public void fromOptional() {
        CQueryAssert.assertEquals(Collections.emptyList(), CQuery.from().nullable(null));
        CQueryAssert.assertEquals(Collections.singletonList(1), CQuery.from().nullable(1));
    }

    @Test
    public void fromValue() {
        CQueryAssert.assertEquals(Collections.singletonList(1), CQuery.from().value(1));
        CQueryAssert.assertEqualsNull(Collections.singletonList(null), CQuery.from().value(null));
    }

    @Test
    public void fromIterable() {
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().iterable(Arrays.asList(1,2,3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().iterable(() -> Arrays.asList(1,2,3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().iterable(3, (a) -> Arrays.asList(1,2,a)));

        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().collection(Arrays.asList(1,2,3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().collection(() -> Arrays.asList(1,2,3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().collection(3, (a) -> Arrays.asList(1,2,a)));

        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().list(Arrays.asList(1,2,3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().list(() -> Arrays.asList(1,2,3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().list(3, (a) -> Arrays.asList(1,2,a)));
    }

    @Test
    public void fromArray() {
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().array(new int[]{1,2,3}));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().array(new Integer[]{1,2,3}));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().array(() -> new Integer[]{1,2,3}));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().array(3, (a) -> new Integer[]{1,2,a}));
    }

    @Test
    public void fromStream() {
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().stream(() -> Stream.of(1,2,3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().stream(3, (a) -> Stream.of(1,2,a)));

    }

    @Test
    public void fromEnumeration() {
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().enumeration(() -> EnumerationUtils.of(1,2,3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().enumeration(3, (a) -> EnumerationUtils.of(1,2,a)));
    }

    @Test
    public void fromSpliterator() {
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().spliterator(() -> Arrays.asList(1,2,3).spliterator()));
    }

    @Test
    public void fromQuery() {
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().query(() -> CQuery.from().values(1, 2, 3)));
        CQueryAssert.assertEquals(Arrays.asList(1,2,3), CQuery.from().query(3, (a) -> CQuery.from().values(1, 2, a)));
    }

    @Test
    public void fromInfinite() {
        Random r = new Random(7);
        CQuery<Integer> infinite = CQuery.from()
            .infinite(() -> r.nextInt(10))
            .limit(5);
        Assert.assertEquals(Arrays.asList(6, 4, 5, 4, 0), infinite.list());
        Assert.assertEquals(Arrays.asList(4, 8, 9, 0, 4), infinite.list());
        Assert.assertEquals(Arrays.asList(0, 2, 8, 1, 5), infinite.list());
    }

    @Test
    public void testBuilder() {
        CQuery<Integer> query = CQuery.<String>builder()
            .with("12", "13", "14")
            .withQuery(CQuery.from(Arrays.asList("21", "22", "23")))
            .withQuery(() -> CQuery.from(Arrays.asList("25", "26")))
            .withQuery("2", a -> CQuery.from(Arrays.asList(a + 7, a + 8, a + 9)))

            .withIterable(Arrays.asList("31", "32", "33"))
            .withIterable(() -> Arrays.asList("35", "36"))
            .withIterable("3", a -> Arrays.asList(a + 7, a + 8, a + 9))

            .withCollection(Arrays.asList("51", "52", "53"))
            .withCollection(() -> Arrays.asList("55", "56"))
            .withCollection("5", a -> Arrays.asList(a + 7, a + 8, a + 9))

            .withArray(new String[]{"61", "62", "63"})
            .withArray(() -> new String[]{"65", "66"})
            .withArray("6", a -> new String[]{a + 7, a + 8, a + 9})
            .build()
            .map(v -> Integer.valueOf(v));

        List<Integer> expected = Arrays.asList(
            12, 13, 14,
            21, 22, 23, 25, 26, 27, 28, 29,
            31, 32, 33, 35, 36, 37, 38, 39,
            51, 52, 53, 55, 56, 57, 58, 59,
            61, 62, 63, 65, 66, 67, 68, 69
        );

        CQueryAssert.assertEquals(expected, query);
    }

    @Test
    public void range() {
        CQueryAssert.assertEquals(Arrays.asList(7,8,9,10,11,12,13,14,15), CQuery.from().range(7, 16));
        CQueryAssert.assertEquals(Arrays.asList(7L,8L,9L,10L,11L,12L,13L,14L,15L), CQuery.from().range(7L, 16L));
    }
}