package com.airlock.iam.common.infrastructure.factory;

import com.airlock.iam.base.api.infrastructure.plugin.ModuleForConfig;
import com.airlock.iam.base.api.infrastructure.plugin.PluginConfigToLogic;
import com.airlock.iam.common.api.domain.model.user.transformation.UsernameTransformation;
import com.airlock.iam.common.application.configuration.credential.SsoTicketRequestAuthenticationConfig;
import com.airlock.iam.common.domain.model.sso.SsoTicketContextDataExtractor;
import com.airlock.iam.common.domain.model.sso.SsoTicketExtractor;
import com.airlock.iam.common.domain.model.sso.SsoTicketKeyRoleExtractor;
import com.airlock.iam.common.domain.model.sso.SsoTicketRoleExtractor;
import com.airlock.iam.common.domain.model.sso.SsoTicketStepSettings;
import com.airlock.iam.common.domain.model.sso.StaticSsoTicketRoleExtractorImpl;
import com.airlock.iam.common.domain.model.transform.UsernameTransformerUsernameTransformation;
import com.airlock.iam.common.domain.service.sso.AcceptedSsoTicketService;
import com.airlock.iam.common.domain.service.sso.SsoTicketService;
import com.airlock.iam.common.domain.service.sso.SsoTicketServiceImpl;
import com.airlock.iam.core.misc.util.ticket.TicketDecoder;
import com.google.inject.Exposed;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

@ModuleForConfig(SsoTicketRequestAuthenticationConfig.class)
public final class SsoTicketRequestAuthenticationModule extends PrivateModule {
   @Provides
   @Exposed
   TicketDecoder provideTicketDecoder(SsoTicketRequestAuthenticationConfig config) {
      return config.getTicketDecoder();
   }

   @Provides
   @Exposed
   UsernameTransformation provideUsernameTransformation(SsoTicketRequestAuthenticationConfig config) {
      return new UsernameTransformerUsernameTransformation(config.getUsernameTransformers());
   }

   @Provides
   List<SsoTicketExtractor> provideTicketExtractors(SsoTicketRequestAuthenticationConfig config, PluginConfigToLogic toLogic) {
      return Stream.of(config.getSsoTicketExtractor()).map(toLogic::getLogic).map(SsoTicketExtractor.class::cast).toList();
   }

   @Provides
   List<SsoTicketRoleExtractor> provideRoleExtractors(SsoTicketRequestAuthenticationConfig config, PluginConfigToLogic toLogic) {
      return Stream.concat(
            Stream.of(config.getStaticRoles()).map(StaticSsoTicketRoleExtractorImpl::new),
            config.getRolesKey().stream().map(List::of).map(SsoTicketKeyRoleExtractor::fromTicketKeys)
         )
         .toList();
   }

   @Provides
   List<SsoTicketContextDataExtractor> provideContextDataExtractors(SsoTicketRequestAuthenticationConfig config, PluginConfigToLogic toLogic) {
      return config.getContextDataExtractors().stream().map(toLogic::getLogic).map(SsoTicketContextDataExtractor.class::cast).toList();
   }

   @Provides
   @Exposed
   SsoTicketStepSettings provideSsoTicketStepSettings(SsoTicketRequestAuthenticationConfig config) {
      return new SsoTicketStepSettings(config.getUsernameKey(), config.getProvidedUsernameKey(), false, false, Optional.empty(), false);
   }

   @Provides
   Optional<AcceptedSsoTicketService> provideAcceptedSsoTicketService() {
      return Optional.empty();
   }

   protected void configure() {
      this.bind(SsoTicketService.class).to(SsoTicketServiceImpl.class);
      this.expose(SsoTicketService.class);
   }
}
