package org.radarcns.auth.authentication;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import org.radarcns.auth.exception.TokenValidationException;
import org.radarcns.auth.security.jwk.JavaWebKey;
import org.radarcns.auth.security.jwk.JavaWebKeySet;
import org.radarcns.auth.token.validation.ECTokenValidationAlgorithm;
import org.radarcns.auth.token.validation.RSATokenValidationAlgorithm;
import org.radarcns.auth.token.validation.TokenValidationAlgorithm;
import org.radarcns.auth.token.validation.deprecated.DeprecatedEcTokenValidationAlgorithm;

public class AlgorithmLoader {

    private static final List<TokenValidationAlgorithm> algorithmList = Arrays.asList(
            new ECTokenValidationAlgorithm(),
            new RSATokenValidationAlgorithm());
    private static final List<TokenValidationAlgorithm> supportedAlgorithmsForPublicKeys = Arrays.asList(
            new DeprecatedEcTokenValidationAlgorithm(),
            new RSATokenValidationAlgorithm());

    private static Algorithm algorithmFromPublicKey(String publicKey) {
        // We deny to trust the public key if the reported algorithm is unknown to us
        // https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
        return loadAlgorithmFromPublicKey(algorithmList, publicKey);
    }

    private static Algorithm loadAlgorithmFromPublicKey(
            List<TokenValidationAlgorithm> supportedAlgorithms, String publicKey) {
        return supportedAlgorithms
                .stream()
                .filter(algorithm -> publicKey.startsWith(algorithm.getKeyHeader()))
                .findFirst()
                .orElseThrow(() ->
                        new TokenValidationException("Unsupported public key: " + publicKey))
                .getAlgorithm(publicKey);
    }

    public static Algorithm loadDeprecatedAlgorithmFromPublicKey(String publicKey) {
        // We deny to trust the public key if the reported algorithm is unknown to us
        // https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
        return loadAlgorithmFromPublicKey(supportedAlgorithmsForPublicKeys, publicKey);
    }

    public static List<Algorithm> loadAlgorithmsFromJavaWebKeys(JavaWebKeySet publicKeyInfo) {
        return publicKeyInfo
                .getKeys()
                .stream()
                .map(JavaWebKey::getValue)
                .map(AlgorithmLoader::algorithmFromPublicKey)
                .collect(Collectors.toList());
    }

    public static JWTVerifier buildVerifier(Algorithm algorithm, String audience) {
        return JWT.require(algorithm)
                .withAudience(audience)
                .build();
    }
}

@@ -992,16 +992,28 @@
 icKeys =
+%0A           
  Arrays.
@@ -1012,32 +1012,32 @@
  Arrays.asList(%0A
-
             new 
@@ -1933,32 +1933,198 @@
 licKey);%0A    %7D%0A%0A
+    /**%0A     * Loads algorithms using deprecated method.%0A     * @param publicKey publicKeys to load algorithms.%0A     * @return instance of %7B@link Algorithm%7D.%0A     */%0A
     public stati
@@ -2453,32 +2453,206 @@
 licKey);%0A    %7D%0A%0A
+    /**%0A     * Loads Algorithms from %7B@link JavaWebKeySet%7D.%0A     * @param publicKeyInfo java web key set to load algorithm.%0A     * @return List of %7B@link Algorithm%7D.%0A     */%0A
     public stati
@@ -2967,24 +2967,278 @@
 ());%0A    %7D%0A%0A
+    /**%0A     * Creates in %7B@link JWTVerifier%7D using Algorithms and audience.%0A     * @param algorithm instance of %7B@link Algorithm%7D to create verifier from.%0A     * @param audience to which audience.%0A     * @return instance of %7B@link JWTVerifier%7D.%0A     */%0A
     public s

add javadoc