package by.binarylifestyle.exception.wrapper.impl.common;

import by.binarylifestyle.exception.wrapper.api.common.UncheckedExceptionWrapper;
import by.binarylifestyle.exception.wrapper.impl.support.WrappingConfiguration;

import java.util.Arrays;
import java.util.Optional;
import java.util.function.Supplier;

public class MappingExceptionWrapper<T> implements UncheckedExceptionWrapper<T, T> {
    private WrappingConfiguration<? extends RuntimeException, ? extends RuntimeException>[] configurations;

    @SafeVarargs
    public MappingExceptionWrapper(WrappingConfiguration<? extends RuntimeException, ? extends RuntimeException>... configurations) {
        this.configurations = configurations;
    }

    @Override
    public Supplier<T> applyTo(Supplier<T> supplier) {
        return new CheckedExceptionWrappingSupplier<>(supplier, configurations);
    }

    private static class CheckedExceptionWrappingSupplier<T> implements Supplier<T> {
        private WrappingConfiguration<? extends RuntimeException, ? extends RuntimeException>[] configurations;
        private Supplier<T> supplier;

        @SafeVarargs
        CheckedExceptionWrappingSupplier(Supplier<T> supplier,
                                         WrappingConfiguration<? extends RuntimeException, ? extends RuntimeException>... configurations) {
            if (configurations.length == 0) {
                throw new IllegalArgumentException("No configuration provided");
            }
            if (!isDistinct(configurations)) {
                throw new IllegalArgumentException("Configuration has repeating elements");
            }
            this.supplier = supplier;
            this.configurations = configurations;
        }

        @Override
        public T get() {
            try {
                return supplier.get();
            } catch (Exception e) {
                Optional<WrappingConfiguration<? extends RuntimeException, ? extends RuntimeException>> wrappingConfigurationOptional =
                        Arrays.stream(configurations)
                            .filter(wrappingConfiguration -> wrappingConfiguration.canWrap(e))
                            .findFirst();
                if (wrappingConfigurationOptional.isPresent()) {
                    throw wrappingConfigurationOptional.get().wrap(e);
                } else {
                    throw e;
                }
            }
        }

        private static boolean isDistinct(WrappingConfiguration[] configuration) {
            long initialSize = configuration.length;
            long distinctSize = Arrays.stream(configuration)
                    .map(WrappingConfiguration::getExceptionToWrap)
                    .distinct()
                    .count();
            return initialSize == distinctSize;
        }
    }
}

@@ -240,16 +240,42 @@
 Arrays;%0A
+import java.util.Objects;%0A
 import j
@@ -687,201 +687,1115 @@
     
-this.configurations = configurations;%0A    %7D%0A%0A    @Override%0A    public Supplier%3CT%3E applyTo(Supplier%3CT%3E supplier) %7B%0A        return new CheckedExceptionWrappingSupplier%3C%3E(supplier, configurations)
+if (configurations == null) %7B%0A            throw new IllegalArgumentException(%22Configurations is null%22);%0A        %7D%0A        if (configurations.length == 0) %7B%0A            throw new IllegalArgumentException(%22No configuration provided%22);%0A        %7D%0A        if (Arrays.stream(configurations).anyMatch(Objects::isNull)) %7B%0A            throw new IllegalArgumentException(%22One or more configurations are null%22);%0A        %7D%0A        if (!isDistinct(configurations)) %7B%0A            throw new IllegalArgumentException(%22Configuration has repeating elements%22);%0A        %7D%0A        this.configurations = configurations;%0A    %7D%0A%0A    @Override%0A    public Supplier%3CT%3E applyTo(Supplier%3CT%3E supplier) %7B%0A        return new CheckedExceptionWrappingSupplier%3C%3E(supplier, configurations);%0A    %7D%0A%0A    private static boolean isDistinct(WrappingConfiguration%5B%5D configuration) %7B%0A        long initialSize = configuration.length;%0A        long distinctSize = Arrays.stream(configuration)%0A                .map(WrappingConfiguration::getExceptionToWrap)%0A                .distinct()%0A                .count();%0A        return initialSize == distinctSize
 ;%0A  
@@ -2264,302 +2264,8 @@
 ) %7B%0A
-            if (configurations.length == 0) %7B%0A                throw new IllegalArgumentException(%22No configuration provided%22);%0A            %7D%0A            if (!isDistinct(configurations)) %7B%0A                throw new IllegalArgumentException(%22Configuration has repeating elements%22);%0A            %7D%0A
     
@@ -3057,394 +3057,8 @@
    %7D
-%0A%0A        private static boolean isDistinct(WrappingConfiguration%5B%5D configuration) %7B%0A            long initialSize = configuration.length;%0A            long distinctSize = Arrays.stream(configuration)%0A                    .map(WrappingConfiguration::getExceptionToWrap)%0A                    .distinct()%0A                    .count();%0A            return initialSize == distinctSize;%0A        %7D
 %0A   

Fix arguments checks for MappingExceptionWrapper