package starter;

import io.zzax.jadeite.console.Console;
import io.zzax.jadeite.test.Checker;
import io.zzax.jadeite.test.MethodDescriptor;

import java.lang.reflect.Modifier;

public class Main {

    public static void main(String[] args) {
        new Main().run();
        new Main().test();
    }

    public void run () {
        {
            int[] numbers = {1, 2};
            int result = sum(numbers);
            Console.println(result);
        }
        // TODO
    }

    public int sum(int[] numbers) {
        int sum = 0;
        for (int i = 0; i < numbers.length; i++) {
            sum += numbers[i];
        }
        return sum;
    }

    // TODO

    public void test() {
        Console.printHeader1("Automatic Test Section");

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(int.class)
                .name("sum")
                .parameters(int[].class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 4};
                    task.when("numbers", numbers);
                    int result = (Integer) method.invoke(Main.this, numbers);
                    task.check("result", result, 28);
                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(boolean.class)
                .name("allPositives")
                .parameters(int[].class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 4};
                    task.when("numbers", numbers);
                    boolean result = (Boolean) method.invoke(Main.this, numbers);
                    task.check("result", result, true);
                });
                Checker.task(task -> {
                    int[] numbers = {-1, 0, -2, 1, 0};
                    task.when("numbers", numbers);
                    boolean result = (Boolean) method.invoke(Main.this, numbers);
                    task.check("result", result, false);
                });

                Checker.task(task -> {
                    int[] numbers = {1, 1, 1, 1, -1};
                    task.when("numbers", numbers);
                    boolean result = (Boolean) method.invoke(Main.this, numbers);
                    task.check("result", result, false);
                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(int.class)
                .name("countLucky")
                .parameters(int[].class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 4};
                    task.when("numbers", numbers);
                    int result = (Integer) method.invoke(Main.this, numbers);
                    task.check("result", result, 0);
                });

                Checker.task(task -> {
                    int[] numbers = {2, 2, 2};
                    task.when("numbers", numbers);
                    int result = (Integer) method.invoke(Main.this, numbers);
                    task.check("result", result, 3);
                });

                Checker.task(task -> {
                    int[] numbers = {2, 7, 2, 8, 2};
                    task.when("numbers", numbers);
                    int result = (Integer) method.invoke(Main.this, numbers);
                    task.check("result", result, 3);
                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(int.class)
                .name("count")
                .parameters(int[].class, int.class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    task.when("value", 3);
                    int result = (Integer) method.invoke(Main.this, numbers, 3);
                    task.check("result", result, 1);
                });

                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    task.when("value", 5);
                    int result = (Integer) method.invoke(Main.this, numbers, 5);
                    task.check("result", result, 0);
                });

                Checker.task(task -> {
                    int[] numbers = {6, 2, 3, 8, 2};
                    task.when("numbers", numbers);
                    task.when("value", 2);
                    int result = (Integer) method.invoke(Main.this, numbers, 2);
                    task.check("result", result, 2);
                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(int.class)
                .name("max")
                .parameters(int[].class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    int result = (Integer) method.invoke(Main.this, numbers);
                    task.check("result", result, 8);
                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(boolean.class)
                .name("increasing")
                .parameters(int[].class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    boolean result = (Boolean) method.invoke(Main.this, numbers);
                    task.check("result", result, false);
                });

                Checker.task(task -> {
                    int[] numbers = {1, 2, 3, 7, 9};
                    task.when("numbers", numbers);
                    boolean result = (Boolean) method.invoke(Main.this, numbers);
                    task.check("result", result, true);
                });

                Checker.task(task -> {
                    int[] numbers = {1, 1, 3, 7, 7};
                    task.when("numbers", numbers);
                    boolean result = (Boolean) method.invoke(Main.this, numbers);
                    task.check("result", result, true);
                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(int.class)
                .name("indexOf")
                .parameters(int[].class, int.class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    task.when("value", 7);
                    int result = (Integer) method.invoke(Main.this, numbers, 7);
                    task.check("result", result, 1);

                });

                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 7, 2};
                    task.when("numbers", numbers);
                    task.when("value", 7);
                    int result = (Integer) method.invoke(Main.this, numbers, 7);
                    task.check("result", result, 1);

                });

                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 7, 2};
                    task.when("numbers", numbers);
                    task.when("value", 5);
                    int result = (Integer) method.invoke(Main.this, numbers, 5);
                    task.check("result", result, -1);

                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(int.class)
                .name("indexOfMax")
                .parameters(int[].class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    int result = (Integer) method.invoke(Main.this, numbers);
                    task.check("result", result, 3);
                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(int[].class)
                .name("indexesOf")
                .parameters(int[].class, int.class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    task.when("target", 8);
                    int[] result = (int[]) method.invoke(Main.this, numbers, 8);
                    int[] expected = {3};
                    task.check("result", result, expected);
                });
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 8};
                    task.when("numbers", numbers);
                    task.when("target", 8);
                    int[] result = (int[]) method.invoke(Main.this, numbers, 8);
                    int[] expected = {3, 4};
                    task.check("result", result, expected);
                });
            });
        }

        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(boolean[].class)
                .name("mapToPass")
                .parameters(int[].class, int.class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    task.when("pass", 3);
                    Object result = method.invoke(Main.this, numbers, 3);
                    boolean[] expected = {true, true, true, true, false};
                    task.check("result", result, expected);
                });
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    task.when("pass", 5);
                    Object result = method.invoke(Main.this, numbers, 3);
                    boolean[] expected = {true, true, false, true, false};
                    task.check("result", result, expected);
                });
            });
        }


        {
            MethodDescriptor descriptor = MethodDescriptor.builder()
                .on(Main.class)
                .modifiers(Modifier.PUBLIC)
                .returning(int[].class)
                .name("slice")
                .parameters(int[].class, int.class, int.class)
                .build();
            Checker.on(descriptor, method -> {
                Checker.task(task -> {
                    int[] numbers = {6, 7, 3, 8, 2};
                    task.when("numbers", numbers);
                    task.when("start", 1);
                    task.when("end", 3);
                    int[] result = (int[]) method.invoke(Main.this, numbers, 1, 3);
                    int[] expected = {7, 3};
                    task.check("result", result, expected);
                });
            });
        }
    }
}
