package io.quarkus.grpc.common.runtime.graal;

import static io.grpc.InternalServiceProviders.getCandidatesViaHardCoded;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;

@SuppressWarnings("unused")
@TargetClass(className = "io.grpc.ServiceProviders")
final class Target_io_grpc_ServiceProviders { // NOSONAR

    @Substitute
    public static <T> List<T> loadAll(
            Class<T> klass,
            Iterable<Class<?>> hardcoded,
            ClassLoader cl,
            final Target_io_grpc_ServiceProviders_PriorityAccessor<T> priorityAccessor) {

        // For loading classes directly instead of using SPI.

        Iterable<T> candidates;
        candidates = getCandidatesViaHardCoded(klass, hardcoded);
        List<T> list = new ArrayList<>();
        for (T current : candidates) {
            if (!priorityAccessor.isAvailable(current)) {
                continue;
            }
            list.add(current);
        }

        // DO NOT USE LAMBDA
        //noinspection Java8ListSort,Convert2Lambda
        Collections.sort(list, Collections.reverseOrder(new Comparator<T>() { // NOSONAR
            @Override
            public int compare(T f1, T f2) {
                int pd = priorityAccessor.getPriority(f1) - priorityAccessor.getPriority(f2);
                if (pd != 0) {
                    return pd;
                }
                return f1.getClass().getName().compareTo(f2.getClass().getName());
            }
        }));
        return Collections.unmodifiableList(list);
    }
}

@TargetClass(className = "io.grpc.ServiceProviders", innerClass = "PriorityAccessor")
interface Target_io_grpc_ServiceProviders_PriorityAccessor<T> { // NOSONAR
    // Just provide access to "io.grpc.ServiceProviders.PriorityAccessor"

    @Alias
    boolean isAvailable(T provider);

    @Alias
    int getPriority(T provider);
}

@SuppressWarnings("unused")
class GrpcSubstitutions {
}

@@ -224,16 +224,60 @@
 il.List;
+%0Aimport java.util.ServiceConfigurationError;
 %0A%0Aimport
@@ -550,16 +550,591 @@
 OSONAR%0A%0A
+    @Substitute%0A    static boolean isAndroid(ClassLoader cl) %7B%0A        return false;%0A    %7D%0A%0A    @Substitute%0A    private static %3CT%3E T createForHardCoded(Class%3CT%3E klass, Class%3C?%3E rawClass) %7B%0A        try %7B%0A            return rawClass.asSubclass(klass).getConstructor().newInstance();%0A        %7D catch (NoSuchMethodException %7C ClassCastException e) %7B%0A            return null;%0A        %7D catch (Throwable t) %7B%0A            throw new ServiceConfigurationError(%0A                    String.format(%22Provider %25s could not be instantiated %25s%22, rawClass.getName(), t), t);%0A        %7D%0A    %7D%0A%0A
     @Sub

Fix missing UdsNettyChannelProvider<init> in native mode