package net.andreinc.mockneat.abstraction;


import net.andreinc.mockneat.utils.ValidationUtils;

import java.util.function.Supplier;
import java.util.stream.IntStream;

import static java.util.stream.IntStream.generate;
import static java.util.stream.IntStream.range;
import static net.andreinc.mockneat.utils.ValidationUtils.isTrue;

public interface MockUnitInt extends MockUnit<Integer> {

    /**
     * <p>Transforms an existing {@code MockUnitInt} into a {@code MockUnit<IntStream>}.</p>
     *
     * <p>The {@code IntStream} will be "infinite" and will contain values generated by the internal {@code MockUnitInt} supplier.</p>
     *
     * @return A new {@code MockUnit<IntStream>}
     */
    default MockUnit<IntStream> intStream() {
        Supplier<IntStream> supp = () -> generate(supplier()::get);
        return () -> supp;
    }

    /**
     * <p>Transforms an existing {@code MockUnitInt} into a {@code MockUnit<int[]>}.</p>
     *
     * <p>The values in the array will be generated using the {@code MockUnitInt} supplier.</p>
     *
     * @param size The size of the Array
     * @return A new {@code MockUnit<int[]>}
     */
    default MockUnit<int[]> arrayPrimitive(int size) {
        isTrue(size>=0, ValidationUtils.SIZE_BIGGER_THAN_ZERO);
        Supplier<int[]> supp = () -> {
            final int[] result = new int[size];
            range(0, size).forEach(i -> result[i] = val());
            return result;
        };
        return () -> supp;
    }

    /**
     * <p>Transforms an existing {@code MockUnitInt} into a {@code MockUnit<Integer[]>}.</p>
     *
     * <p>The values in the array will be generated using the {@code MockUnitInt} supplier.</p>
     *
     * @param size The size of the Array
     * @return A new {@code MockUnit<Integer[]>}
     */
    default MockUnit<Integer[]> array(int size) {
        isTrue(size>=0, ValidationUtils.SIZE_BIGGER_THAN_ZERO);
        Supplier<Integer[]> supp = () -> {
            final Integer[] result = new Integer[size];
            range(0, size).forEach(i -> result[i] = val());
            return result;
        };
        return () -> supp;
    }
}
