package io.quarkus.elytron.security.jdbc;

import java.security.Provider;
import java.util.function.Supplier;

import javax.sql.DataSource;

import org.wildfly.security.auth.realm.jdbc.JdbcSecurityRealm;
import org.wildfly.security.auth.realm.jdbc.JdbcSecurityRealmBuilder;
import org.wildfly.security.auth.realm.jdbc.QueryBuilder;
import org.wildfly.security.auth.realm.jdbc.mapper.AttributeMapper;
import org.wildfly.security.auth.server.SecurityRealm;
import org.wildfly.security.password.WildFlyElytronPasswordProvider;

import io.quarkus.arc.Arc;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.annotations.Recorder;

@Recorder
public class JdbcRecorder {

    private static final Provider[] PROVIDERS = new Provider[] { new WildFlyElytronPasswordProvider() };

    /**
     * Create a runtime value for a {@linkplain JdbcSecurityRealm}
     *
     * @param config - the realm config
     * @return - runtime value wrapper for the SecurityRealm
     */
    public RuntimeValue<SecurityRealm> createRealm(JdbcSecurityRealmConfig config) {
        Supplier<Provider[]> providers = new Supplier<Provider[]>() {
            @Override
            public Provider[] get() {
                return PROVIDERS;
            }
        };
        JdbcSecurityRealmBuilder builder = JdbcSecurityRealm.builder().setProviders(providers);
        PrincipalQueriesConfig principalQueries = config.principalQueries;
        registerPrincipalQuery(principalQueries.defaultPrincipalQuery, builder);
        principalQueries.namedPrincipalQueries
                .forEach((name, principalQuery) -> registerPrincipalQuery(principalQuery, builder));
        return new RuntimeValue<>(builder.build());
    }

    private void registerPrincipalQuery(PrincipalQueryConfig principalQuery, JdbcSecurityRealmBuilder builder) {

        QueryBuilder queryBuilder = builder.principalQuery(principalQuery.sql.orElseThrow(
                () -> new IllegalStateException("quarkus.security.jdbc.principal-query.sql property must be set")))
                .from(getDataSource(principalQuery));

        AttributeMapper[] mappers = principalQuery.attributeMappings.entrySet()
                .stream()
                .map(entry -> new AttributeMapper(entry.getValue().index, entry.getValue().to))
                .toArray(size -> new AttributeMapper[size]);
        queryBuilder.withMapper(mappers);

        if (principalQuery.clearPasswordMapperConfig.enabled) {
            queryBuilder.withMapper(principalQuery.clearPasswordMapperConfig.toPasswordKeyMapper());
        }
        if (principalQuery.bcryptPasswordKeyMapperConfig.enabled) {
            queryBuilder.withMapper(principalQuery.bcryptPasswordKeyMapperConfig.toPasswordKeyMapper());
        }
    }

    private DataSource getDataSource(PrincipalQueryConfig principalQuery) {
        return (DataSource) principalQuery.datasource
                // this is not correct, it should be something like 'Arc.container().instance(javax.sql.DataSource.class, new DataSource.DataSourceLiteral(name))'
                .map(name -> Arc.container().instance(name).get())
                .orElse(Arc.container().instance(DataSource.class).get());
    }
}

@@ -2838,28 +2838,12 @@
     
-return (DataSource) 
+if (
 prin
@@ -2867,171 +2867,219 @@
 urce
-%0A                // this is not correct, it should be something like 'Arc.container().instance(javax.sql.DataSource.class, new DataSource.DataSourceLiteral(name
+.isPresent()) %7B%0A            return Arc.container()%0A                    .instance(DataSource.class,%0A                            new io.quarkus.agroal.DataSource.DataSourceLiteral(principalQuery.datasource.get()
 ))
-'
 %0A   
@@ -3095,58 +3095,19 @@
     
-.map(name -%3E Arc.container().instance(name)
+    
 .get()
-)
+;
 %0A   
@@ -3111,24 +3111,27 @@
         
+%7D%0A%0A
         
 .orElse(
@@ -3126,16 +3126,15 @@
     
-.orElse(
+return 
 Arc.
@@ -3177,17 +3177,16 @@
 s).get()
-)
 ;%0A    %7D%0A

Use better style CDI when obtaining the DataSource