package com.telephoners.krakyournet.ctf;

import com.bazaarvoice.dropwizard.webjars.WebJarBundle;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.telephoners.krakyournet.ctf.beans.Team;
import com.telephoners.krakyournet.ctf.beans.User;
import com.telephoners.krakyournet.ctf.commands.PurgeDatabaseCommand;
import com.telephoners.krakyournet.ctf.commands.RegisterTasksCommand;
import com.telephoners.krakyournet.ctf.commands.RegisterTeamsCommand;
import com.telephoners.krakyournet.ctf.core.ApplicationConfiguration;
import com.telephoners.krakyournet.ctf.logging.LoggingFilter;
import com.telephoners.krakyournet.ctf.modules.ApplicationModule;
import com.telephoners.krakyournet.ctf.repositories.Repository;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.jersey.setup.JerseyEnvironment;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;

import java.io.IOException;
import java.util.List;
import java.util.stream.Stream;

public class CTFApplication extends Application<ApplicationConfiguration>
{
    private Injector injector;

    @Override
    public void initialize(final Bootstrap<ApplicationConfiguration> bootstrap)
    {
        bootstrap.addBundle(new AssetsBundle("/assets_build", "/", "index.html"));
        bootstrap.addCommand(new PurgeDatabaseCommand());
        bootstrap.addCommand(new RegisterTasksCommand());
        bootstrap.addCommand(new RegisterTeamsCommand());
        Stream.of("org.webjars.npm", "org.webjars.bower")
                .map(WebJarBundle::new)
                .forEach(bootstrap::addBundle);
    }

    private void registerResources(Environment environment) throws IOException
    {
        JerseyEnvironment jersey = environment.jersey();
        final ClassPath classPath = ClassPath.from(this.getClass().getClassLoader());
        ImmutableSet<ClassPath.ClassInfo> resourceClasses = classPath.getTopLevelClasses("com.telephoners.krakyournet.ctf.resources");
//        resourceClasses.stream()
//                .forEach(classInfo -> jersey.register(injector.getInstance(classInfo.load())));
    }

    private void registerAuthFeatures(Environment environment)
    {
//        environment.jersey().register(new AuthDynamicFeature(
//                new BasicCredentialAuthFilter.Builder<User>()
//                        .setAuthenticator(injector.getInstance(UserAuthenticator.class))
//                        .buildAuthFilter()));
        environment.jersey().register(RolesAllowedDynamicFeature.class);
        environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));
    }

    private void registerFilters(Environment environment){
        environment.jersey().register(new LoggingFilter());
    }

    @Override
    public void run(ApplicationConfiguration applicationConfiguration, Environment environment) throws Exception
    {
        injector = createInjector(applicationConfiguration);


        Team team = new Team();
        team.setName("asdf");
        team.setDescription("sadf");
        User user = new User("asdf", "asdf", "asdffg", false);

        Repository<Team> teamRepository = injector.getInstance(Key.get(new TypeLiteral<Repository<Team>>(){}));
        Repository<User> userRepository = injector.getInstance(Key.get(new TypeLiteral<Repository<User>>(){}));

        teamRepository.add(team);
        List<Team> all1 = teamRepository.getAll();
        userRepository.add(user);
        List<User> all = userRepository.getAll();


        registerAdmins(applicationConfiguration);
        registerResources(environment);
        registerAuthFeatures(environment);
        registerFilters(environment);
    }

    private void registerAdmins(ApplicationConfiguration applicationConfiguration)
    {
//        UsersRepository usersRepository = injector.getInstance(UsersRepository.class);
//        applicationConfiguration.getAdmins().forEach(usersRepository::add);
    }

    private Injector createInjector(ApplicationConfiguration applicationConfiguration)
    {
        return Guice.createInjector(new ApplicationModule(applicationConfiguration));
    }

    public static void main(String[] args) throws Exception
    {
        new CTFApplication().run(args);
    }
}
