package net.ranides.assira.collection.query;

import net.ranides.test.CQueryAssert;
import net.ranides.test.mockup.query.CQueryTypes;
import org.junit.Test;

import net.ranides.assira.collection.IntComparator;

import java.util.Arrays;
import java.util.List;

import static org.junit.Assert.assertEquals;

public class CQueryFunctionTest {

    @Test
    public void simple() {
        CQueryFunction<String, Integer> filter = CQueryFunction.<String>prepare()
            .filter(s -> s.matches("[0-9,; ]+"))
            .flatArray(s -> s.split("[; ,]+"))
            .map(Integer::valueOf)
            .sort(IntComparator.DESC);

        CQuery<String> input = CQuery.from().values("1,2,8", "o,t,h,er", "6 9 4", "q", "7;3");
        List<Integer> list1 = input.apply(filter).list();
        assertEquals(Arrays.asList(9,8,7,6,4,3,2,1), list1);

        List<Integer> list2 = CQuery.from()
            .values("hello", "world", "end", "here", "!")
            .map(String::length)
            .map(String::valueOf)
            .apply(filter)
            .list();
        assertEquals(Arrays.asList(5, 5, 4, 3, 1), list2);
    }

    @Test
    public void generic() {
        CQueryFunction<CharSequence, Integer> f1 = CQueryFunction.<CharSequence>prepare().map(s -> Integer.valueOf(s.toString()));
        CQueryFunction<CQueryTypes.Text, Integer> f2 = CQueryFunction.<CQueryTypes.Text>prepare().map(s -> Integer.valueOf(s.toString()));
        CQueryFunction<CQueryTypes.TextValue, Integer> f3 = CQueryFunction.<CQueryTypes.TextValue>prepare().map(s -> Integer.valueOf(s.text.toString()));

        CQuery<CharSequence> s1 = CQuery.from().values("1", "2", "5", "8");
        CQuery<CQueryTypes.Text> s2 = CQuery.from().values("1", "2", "5", "8").map(CQueryTypes.TextValue::new);
        CQuery<CQueryTypes.TextValue> s3 = CQuery.from().values("1", "2", "5", "8").map(CQueryTypes.TextValue::new);

        List<Integer> expect = Arrays.asList(1, 2, 5, 8);

        assertEquals(expect, s1.apply(f1).list());
//        assertEquals(expect, s1.apply(f2).list()); // compilation error expected
//        assertEquals(expect, s1.apply(f3).list()); // compilation error expected

        assertEquals(expect, s2.apply(f1).list());
        assertEquals(expect, s2.apply(f2).list());
//        assertEquals(expect, s2.apply(f3).list()); // compilation error expected

        assertEquals(expect, s3.apply(f1).list());
        assertEquals(expect, s3.apply(f2).list());
        assertEquals(expect, s3.apply(f3).list());
    }

    @Test
    public void skipFilterSlice() {
        CQueryFunction<Integer, Integer> func1 = CQueryFunction.<Integer>prepare()
            // 5 .. 49
            .skip(5)
            // 5,7,8,10,11,13,14,16,18, ... 41,43,44,46,47,49
            .filter(v -> v % 3 != 0)
            // 16 ... 89
            .slice(7, 22);

        List<Integer> exp1 = Arrays.asList(16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37);

        CQueryAssert.assertEquals(exp1, CQuery.from().range(0, 50).apply(func1));

        CQueryFunction<Integer, Integer> func2 = CQueryFunction.<Integer>prepare()
            // 0 .. 24
            .limit(v -> v < 25)
            // 100 .. 124
            .map(v -> 100 + v)
            // 106 .. 119
            .filterEach((i,v) -> i>5 && i<20)
            // 107,109,111 .. 119
            .discard(v -> v%2 ==0)
            .sort(IntComparator.DESC);

        List<Integer> exp2 = Arrays.asList(119, 117, 115, 113, 111, 109, 107);
        CQueryAssert.assertEquals(exp2, CQuery.from().range(0, 50).apply(func2));
    }


}