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

import com.airlock.iam.authentication.application.configuration.rememberme.RememberMeUserIdentifyingStepConfig;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeCookie;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeRequest;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeResponse;
import com.airlock.iam.authentication.domain.service.rememberme.RememberMeJspUserSecretPersisterService;
import com.airlock.iam.authentication.domain.service.rememberme.RememberMeJspUserSecretPersisterServiceImpl;
import com.airlock.iam.authentication.domain.service.rememberme.RememberMeTokenGenerationService;
import com.airlock.iam.authentication.domain.service.rememberme.RememberMeTokenGenerationServiceImpl;
import com.airlock.iam.authentication.domain.service.rememberme.RememberMeTokenVerificationService;
import com.airlock.iam.authentication.domain.service.rememberme.RememberMeTokenVerificationServiceImpl;
import com.airlock.iam.authentication.infrastructure.rememberme.RememberMeRequestImpl;
import com.airlock.iam.authentication.infrastructure.rememberme.RememberMeResponseImpl;
import com.airlock.iam.base.api.infrastructure.plugin.ModuleForConfig;
import com.airlock.iam.common.api.domain.model.authmethod.AuthenticationMethod;
import com.airlock.iam.common.application.configuration.rememberme.JspRememberMeConfig;
import com.airlock.iam.common.application.configuration.rememberme.RememberMeConfig;
import com.airlock.iam.common.domain.model.request.ContextPath;
import com.airlock.iam.core.misc.impl.authen.AuthenticationMethodFactory;
import com.airlock.iam.database.infrastructure.JooqConfig;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeTokenLifetime;
import com.airlock.iam.flow.shared.domain.model.rememberme.RememberMeTokenRepository;
import com.airlock.iam.flow.shared.infrastructure.rememberme.RememberMeTokenRepositoryImpl;
import com.google.inject.Exposed;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import java.util.Optional;

@ModuleForConfig(RememberMeUserIdentifyingStepConfig.class)
public class RememberMeUserIdentifyingStepModule extends PrivateModule {
   @Provides
   @Exposed
   AuthenticationMethod provideAuthenticationMethod(RememberMeUserIdentifyingStepConfig config) {
      return AuthenticationMethodFactory.authMethodFor(config.getAuthenticationMethodId());
   }

   @Provides
   @Exposed
   RememberMeTokenLifetime provideRememberMeTokenLifetime(RememberMeConfig config) {
      return RememberMeTokenLifetime.lifetime(config.getRememberMeLifetimeDuration(), config.getRememberMeIdleTimeoutDuration());
   }

   @Provides
   @Exposed
   Optional<JspRememberMeConfig> provideJspRememberMeConfig(RememberMeUserIdentifyingStepConfig config) {
      return config.getMigrateJspRememberMeCookies();
   }

   @Provides
   Optional<RememberMeCookie.RememberMeCookieBuilder> provideRememberMeJspCookieBuilder(
      Optional<JspRememberMeConfig> jspRememberMeConfig, ContextPath contextPath
   ) {
      return jspRememberMeConfig.map(
         config -> RememberMeCookie.builder().name(config.getCookieName()).domain(config.getCookieDomain()).path(config.getCookiePath(contextPath.getPath()))
      );
   }

   @Provides
   Optional<RememberMeJspUserSecretPersisterService> providerRememberMeJspUserSecretRepository(Optional<JspRememberMeConfig> jspRememberMeConfig) {
      return jspRememberMeConfig.map(c -> RememberMeJspUserSecretPersisterServiceImpl.builder().credentialPersister(c.getCredentialPersister()).build());
   }

   @Provides
   Optional<RememberMeTokenLifetime> provideJspTokenLifeTime(Optional<JspRememberMeConfig> jspRememberMeConfig) {
      return jspRememberMeConfig.map(c -> RememberMeTokenLifetime.lifetime(c.getCookieLifetimeDuration(), c.getCookieIdleTimeoutDuration()));
   }

   @Provides
   JooqConfig provideJooqConfig(RememberMeConfig config) {
      return config.getRepository().jooqConfig();
   }

   protected void configure() {
      this.bind(RememberMeRequest.class).to(RememberMeRequestImpl.class);
      this.expose(RememberMeRequest.class);
      this.bind(RememberMeResponse.class).to(RememberMeResponseImpl.class);
      this.expose(RememberMeResponse.class);
      this.bind(RememberMeTokenRepository.class).to(RememberMeTokenRepositoryImpl.class);
      this.expose(RememberMeTokenRepository.class);
      this.bind(RememberMeTokenVerificationService.class).to(RememberMeTokenVerificationServiceImpl.class);
      this.expose(RememberMeTokenVerificationService.class);
      this.bind(RememberMeTokenGenerationService.class).to(RememberMeTokenGenerationServiceImpl.class);
      this.expose(RememberMeTokenGenerationService.class);
   }
}
