package com.airlock.iam.common.infrastructure;

import com.airlock.iam.base.api.domain.model.event.DomainEventSubscriber;
import com.airlock.iam.common.api.infrastructure.ApplicationComponentProvider;
import com.airlock.iam.common.api.infrastructure.ApplicationInitializationHook;
import com.airlock.iam.common.api.infrastructure.mapper.MapperConfiguration;
import com.google.inject.Module;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Function;

public final class AggregateApplicationComponentProvider implements ApplicationComponentProvider {
   private final Collection<Class<?>> jaxRsComponents;
   private final Collection<Class<? extends Module>> guiceModules;
   private final Collection<Class<?>> pluginLogics;
   private final Collection<Class<? extends DomainEventSubscriber>> domainEventSubscribers;
   private final Collection<Consumer<MapperConfiguration>> beanMappers;
   private final Collection<Class<? extends ApplicationInitializationHook>> initializationHooks;

   public AggregateApplicationComponentProvider(Collection<ApplicationComponentProvider> providers) {
      this.jaxRsComponents = mapComponents(ApplicationComponentProvider::jaxRsComponents, providers);
      this.guiceModules = mapComponents(ApplicationComponentProvider::guiceModules, providers);
      this.pluginLogics = mapComponents(ApplicationComponentProvider::pluginLogics, providers);
      this.domainEventSubscribers = mapComponents(ApplicationComponentProvider::domainEventSubscribers, providers);
      this.beanMappers = mapComponents(ApplicationComponentProvider::beanMappers, providers);
      this.initializationHooks = mapComponents(ApplicationComponentProvider::initializationHooks, providers);
   }

   private static <T> Collection<T> mapComponents(
      Function<ApplicationComponentProvider, Collection<T>> mapper, Collection<ApplicationComponentProvider> providers
   ) {
      return providers.stream().map(mapper).flatMap(Collection::stream).distinct().toList();
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public Collection<Class<?>> jaxRsComponents() {
      return this.jaxRsComponents;
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public Collection<Class<? extends Module>> guiceModules() {
      return this.guiceModules;
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public Collection<Class<?>> pluginLogics() {
      return this.pluginLogics;
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public Collection<Class<? extends DomainEventSubscriber>> domainEventSubscribers() {
      return this.domainEventSubscribers;
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public Collection<Consumer<MapperConfiguration>> beanMappers() {
      return this.beanMappers;
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public Collection<Class<? extends ApplicationInitializationHook>> initializationHooks() {
      return this.initializationHooks;
   }
}
