package ru.yandex.webmaster3.core.metrics.externals;

import ru.yandex.webmaster3.core.util.JavaMethodWitness;
import ru.yandex.webmaster3.core.util.functional.ThrowingRunnable;
import ru.yandex.webmaster3.core.util.functional.ThrowingSupplier;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @author avhaliullin
 */
abstract class ExternalAPIServiceBase {
    abstract String getServiceName();

    protected <R, E extends Exception> R trackQuery(JavaMethodWitness methodWitness,
                                                    Predicate<Exception> userExceptionPredicate,
                                                    ThrowingSupplier<R, E> call) throws E {
        return ExternalAPICallTracker.trackQuery(
                getServiceName(),
                ExternalDependencyUtils.getMethodName(methodWitness),
                userExceptionPredicate,
                call
        );
    }

    protected <R, E extends Exception> R trackQuery(JavaMethodWitness methodWitness,
                                                    Function<Exception, ExternalAPICallTracker.Status> exceptionMappingFunction,
                                                    ThrowingSupplier<R, E> call) throws E {
        return ExternalAPICallTracker.trackQuery(
                getServiceName(),
                ExternalDependencyUtils.getMethodName(methodWitness),
                exceptionMappingFunction,
                call
        );
    }

    protected <E extends Exception> void trackExecution(JavaMethodWitness methodWitness,
                                                        Predicate<Exception> userExceptionPredicate,
                                                        ThrowingRunnable<E> call) throws E {
        ExternalAPICallTracker.trackExecution(
                getServiceName(),
                ExternalDependencyUtils.getMethodName(methodWitness),
                userExceptionPredicate,
                call
        );
    }

    protected <E extends Exception> void trackExecution(JavaMethodWitness methodWitness,
                                                        Function<Exception, ExternalAPICallTracker.Status> exceptionMappingFunction,
                                                        ThrowingRunnable<E> call) throws E {
        ExternalAPICallTracker.trackExecution(
                getServiceName(),
                ExternalDependencyUtils.getMethodName(methodWitness),
                exceptionMappingFunction,
                call
        );
    }

    protected static final Predicate<Exception> ALL_ERRORS_INTERNAL = ign -> false;

    @SafeVarargs
    protected static Predicate<Exception> userExceptions(Class<? extends Exception> e0, Class<? extends Exception>... es) {
        List<Class<?>> userExceptions = new ArrayList<>(es.length + 1);
        userExceptions.addAll(Arrays.asList(es));
        userExceptions.add(e0);
        return e -> {
            Class<? extends Exception> exClass = e.getClass();
            for (Class<?> ueClass : userExceptions) {
                if (ueClass.isAssignableFrom(exClass)) {
                    return true;
                }
            }
            return false;
        };
    }

}
