package com.airlock.iam.admin.infrastructure.factory.prot;

import com.airlock.iam.admin.application.configuration.oauth2.OAuth2TokenController;
import com.airlock.iam.admin.application.service.user.OAuth2AdminService;
import com.airlock.iam.admin.domain.model.administrator.permissions.AdminappAction;
import com.airlock.iam.admin.domain.model.authmethod.AuthenticationMethod;
import com.airlock.iam.admin.domain.model.token.TokenController;
import com.airlock.iam.admin.domain.model.token.oauth2.OAuth2AuthenticationMethod;
import com.airlock.iam.admin.domain.model.token.oauth2.OAuth2TokenControllerSettings;
import com.airlock.iam.admin.domain.service.access.AdminappAccessController;
import com.airlock.iam.base.api.domain.model.exception.ServiceConfigurationException;
import com.airlock.iam.core.misc.persistency.token.TokenDataProvider;
import com.airlock.iam.oauth2.application.configuration.session.OAuth2SessionRepositoryConfig;
import com.airlock.iam.oauth2.domain.model.session.OAuth2GlobalSessionsRepository;
import com.airlock.iam.oauth2.infrastructure.repository.OAuth2GlobalSessionsRepositoryImpl;
import com.airlock.iam.oauth2.infrastructure.repository.OAuth2SessionRepositorySettings;
import com.google.inject.Exposed;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import com.google.inject.servlet.RequestScoped;
import jakarta.inject.Named;
import jakarta.inject.Provider;
import java.util.Optional;

public class OAuth2ServiceModule extends PrivateModule {
   @Provides
   TokenDataProvider provideTokenDataProvider(OAuth2TokenController tokenController) {
      return (TokenDataProvider)ServiceConfigurationException.checkNotNull(
         tokenController.tokenDataProvider(), "A Token Data Provider in OAuth 2.0 Token Controller must be configured"
      );
   }

   @Provides
   OAuth2TokenController provideTokenController(Provider<TokenController.TokenControllers> tokenControllers) {
      Optional<OAuth2TokenController> tokenController = ((TokenController.TokenControllers)tokenControllers.get()).ofId("OAUTH2");
      return (OAuth2TokenController)ServiceConfigurationException.checkPresent(tokenController, "OAuth 2.0 Token controller must be configured.");
   }

   @Provides
   OAuth2SessionRepositoryConfig provideSessionRepositoryConfig(OAuth2TokenController tokenController) {
      return tokenController.sessionRepository();
   }

   @Provides
   OAuth2SessionRepositorySettings provideOAuth2SessionRepositorySettings(OAuth2SessionRepositoryConfig sessionRepositoryConfig) {
      return new OAuth2SessionRepositorySettings(sessionRepositoryConfig.jooqConfig(), false);
   }

   @Exposed
   @Provides
   @RequestScoped
   @Named("OAUTH2")
   AuthenticationMethod provideAuthMethod(OAuth2TokenController controller, OAuth2AdminService service, AdminappAccessController accessController) {
      return OAuth2AuthenticationMethod.builder().settings(buildOAuthConsentSettings(controller, accessController)).service(service).build();
   }

   private static OAuth2TokenControllerSettings buildOAuthConsentSettings(OAuth2TokenController controller, AdminappAccessController accessController) {
      return new OAuth2TokenControllerSettings(
         controller.getConfiguredId(), controller.consentRepository().isPresent() && accessController.isActionAllowed(AdminappAction.MANAGE_OAUTH_CONSENTS)
      );
   }

   protected void configure() {
      this.bind(OAuth2AdminService.class).in(RequestScoped.class);
      this.expose(OAuth2AdminService.class);
      this.bind(OAuth2GlobalSessionsRepository.class).to(OAuth2GlobalSessionsRepositoryImpl.class);
   }
}
