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

import com.airlock.iam.authentication.application.configuration.ui.AuthenticationUiConfig;
import com.airlock.iam.authentication.application.configuration.ui.AuthenticationUiConfigs;
import com.airlock.iam.authentication.domain.model.session.CurrentApplicationId;
import com.airlock.iam.authentication.infrastructure.mapper.AuthenticationUiMetadataProvider;
import com.airlock.iam.authentication.infrastructure.service.ui.AuthenticationUiRepository;
import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.common.api.domain.model.user.User;
import com.airlock.iam.common.domain.model.principal.UserPrincipal;
import com.airlock.iam.common.infrastructure.delay.ResponseDelayCondition;
import com.airlock.iam.core.misc.authorization.AccessController;
import com.airlock.iam.flow.api.domain.model.flow.ApplicationId;
import com.airlock.iam.flow.shared.domain.service.MetadataProvider;
import com.airlock.iam.flow.shared.infrastructure.service.FailureResponseDelayCondition;
import com.airlock.iam.flow.ui.application.configuration.FlowUiConfig;
import com.airlock.iam.flow.ui.infrastructure.service.ui.DefaultStepUiConfigRepository;
import com.google.inject.Exposed;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import com.google.inject.servlet.RequestScoped;
import java.util.Optional;

public class AuthenticationInfrastructureModule extends PrivateModule {
   @Provides
   @Exposed
   Optional<AccessController> provideAccessController() {
      return Optional.empty();
   }

   @Provides
   @RequestScoped
   @Exposed
   AuthenticationUiConfig provideAuthenticationUiConfig(Optional<AuthenticationUiConfigs> uiConfigs, Optional<CurrentApplicationId> applicationId) {
      ApplicationId appId = ViolationException.checkPresent(applicationId.map(CurrentApplicationId::applicationId), "No current application ID available");
      return ViolationException.checkPresent(
         uiConfigs.flatMap(c -> c.byApplicationId(appId)), String.format("No UI config found for application with ID '%s'", appId.getApplicationId())
      );
   }

   @Provides
   @RequestScoped
   @Exposed
   Optional<AuthenticationUiConfig> provideOptionalAuthenticationUiConfig(
      Optional<AuthenticationUiConfigs> uiConfigs, Optional<CurrentApplicationId> applicationId
   ) {
      return applicationId.flatMap(appId -> uiConfigs.flatMap(c -> c.byApplicationId(appId.applicationId())));
   }

   protected void configure() {
      this.bind(ResponseDelayCondition.class).to(FailureResponseDelayCondition.class).in(RequestScoped.class);
      this.expose(ResponseDelayCondition.class);
      this.bind(DefaultStepUiConfigRepository.class).to(AuthenticationUiRepository.class).in(RequestScoped.class);
      this.expose(DefaultStepUiConfigRepository.class);
      this.bind(FlowUiConfig.class).to(AuthenticationUiConfig.class).in(RequestScoped.class);
      this.expose(FlowUiConfig.class);
      this.bind(MetadataProvider.class).to(AuthenticationUiMetadataProvider.class);
      this.expose(MetadataProvider.class);
      this.bind(User.class).to(UserPrincipal.class).in(RequestScoped.class);
      this.expose(User.class);
   }
}
