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

import com.airlock.iam.authentication.application.configuration.password.VoluntaryPasswordChangeStepConfig;
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.e2ee.E2eEncryptionSession;
import com.airlock.iam.common.domain.model.password.policy.PasswordPolicyAdapter;
import com.airlock.iam.common.domain.model.password.policy.UserPasswordPolicy;
import com.airlock.iam.common.domain.model.password.repository.UserPasswordRepository;
import com.airlock.iam.core.misc.impl.authen.AuthenticationMethodFactory;
import com.airlock.iam.flow.api.domain.model.session.FlowSession;
import com.airlock.iam.flow.infrastructure.step.StepSessionModuleHelper;
import com.airlock.iam.flow.shared.domain.model.password.PasswordChangeSettings;
import com.airlock.iam.flow.shared.domain.model.password.PasswordChangeStep;
import com.airlock.iam.flow.shared.domain.model.password.PasswordChangeStepSession;
import com.airlock.iam.flow.shared.domain.service.password.PasswordChangeService;
import com.google.inject.Exposed;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import java.util.Optional;

@ModuleForConfig(VoluntaryPasswordChangeStepConfig.class)
public final class AuthenticationVoluntaryPasswordChangeStepModule extends PrivateModule {
   @Exposed
   @Provides
   PasswordChangeStepSession providePasswordChangeSession(FlowSession flowSession) {
      return StepSessionModuleHelper.retrieveStepSession(flowSession, PasswordChangeStepSession.class);
   }

   @Provides
   UserPasswordRepository provideUserPasswordRepository(VoluntaryPasswordChangeStepConfig config, PluginConfigToLogic toLogic) {
      return toLogic.getLogic(config.getPasswordRepository());
   }

   @Exposed
   @Provides
   UserPasswordPolicy createUserPasswordPolicy(VoluntaryPasswordChangeStepConfig config) {
      return new PasswordPolicyAdapter(
         invocation -> config.getPasswordPolicy()
            .validatePasswordOnVoluntaryChange(
               invocation.getPassword().getValue(), invocation.getOldPassword().orElseThrow().getValue(), invocation.getHashFunction(), invocation.getUser()
            )
      );
   }

   @Exposed
   @Provides
   PasswordChangeSettings providePasswordChangeSettings(VoluntaryPasswordChangeStepConfig config) {
      return PasswordChangeSettings.builder()
         .oldPasswordAttempts(config.getOldPasswordAttempts())
         .oldPasswordRequired(config.isOldPasswordRequired())
         .passwordAttributeName(config.getPasswordAttributeName())
         .authenticationMethod(AuthenticationMethodFactory.authMethodFor(config.getAuthenticationMethodId()))
         .redFlag(Optional.empty())
         .e2eEncryptionUseCase(E2eEncryptionSession.E2eEncryptionUseCase.VOLUNTARY_PASSWORD_CHANGE)
         .stepAction(PasswordChangeStep.VoluntaryPasswordChangeStepActions.PASSWORD_CHANGE_REQUIRED)
         .description("Voluntary Password Change Step")
         .build();
   }

   protected void configure() {
      this.bind(PasswordChangeService.class);
      this.expose(PasswordChangeService.class);
   }
}
