package com.airlock.iam.flow.shared.domain.model.radiusotp;

import com.airlock.iam.authentication.api.domain.model.step.AuthenticationStepResult;
import com.airlock.iam.authentication.api.domain.model.step.AuthenticationStepResultFactory;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.common.api.domain.model.authentication.factor.AuthenticationFactorDetail;
import com.airlock.iam.common.api.domain.model.authmethod.AuthenticationMethod;
import com.airlock.iam.common.api.domain.model.otp.UnverifiedOtp;
import com.airlock.iam.core.domain.model.authentication.factor.KnownAuthenticationFactorDetail;
import com.airlock.iam.core.domain.model.authentication.method.KnownAuthenticationMethods;
import com.airlock.iam.flow.api.domain.model.step.StepSession;
import com.airlock.iam.flow.shared.application.configuration.radiusotp.RadiusOtpAuthStepConfig;
import com.airlock.iam.flow.shared.domain.model.otp.GenericOtpCheckingStep;
import com.airlock.iam.flow.shared.domain.model.otp.OtpCheckingAdapter;
import com.google.common.annotations.VisibleForTesting;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Optional;

@LogicForConfig(RadiusOtpAuthStepConfig.class)
public class RadiusOtpCheckingStepImpl implements GenericOtpCheckingStep {
   private final Provider<OtpCheckingAdapter> otpCheck;
   private final Provider<AuthenticationMethod> authMethod;

   @Inject
   public RadiusOtpCheckingStepImpl(Provider<OtpCheckingAdapter> otpCheck, Provider<AuthenticationMethod> authMethod) {
      this.otpCheck = otpCheck;
      this.authMethod = authMethod;
   }

   @Override
   public Optional<StepSession> createSession() {
      return ((OtpCheckingAdapter)this.otpCheck.get()).createSession();
   }

   @Override
   public AuthenticationStepResult initialize() {
      return ((OtpCheckingAdapter)this.otpCheck.get()).initialize(this.stepResultFactory());
   }

   public AuthenticationStepResult checkOtp(UnverifiedOtp otp) {
      return ((OtpCheckingAdapter)this.otpCheck.get()).checkOtp(otp, this.stepResultFactory());
   }

   @Override
   public AuthenticationMethod getAuthenticationMethod() {
      return (AuthenticationMethod)this.authMethod.get();
   }

   @Override
   public String getDescription() {
      return "Radius Otp Authentication Step";
   }

   public AuthenticationStepResultFactory stepResultFactory() {
      return AuthenticationStepResultFactory.forFactorDetail(findFactorDetailForRadius(((AuthenticationMethod)this.authMethod.get()).getId()));
   }

   @VisibleForTesting
   static AuthenticationFactorDetail findFactorDetailForRadius(String method) {
      if (KnownAuthenticationMethods.SECURID.getId().equals(method)) {
         return KnownAuthenticationFactorDetail.OTP_SECURID;
      } else if (KnownAuthenticationMethods.HW_OTP.getId().equals(method)) {
         return KnownAuthenticationFactorDetail.OTP_HARDWARE;
      } else {
         return KnownAuthenticationMethods.SW_OTP.getId().equals(method)
            ? KnownAuthenticationFactorDetail.OTP_SOFTWARE
            : KnownAuthenticationFactorDetail.OTP_RADIUS;
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   public static RadiusOtpCheckingStepImpl.RadiusOtpCheckingStepImplBuilder builder() {
      return new RadiusOtpCheckingStepImpl.RadiusOtpCheckingStepImplBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class RadiusOtpCheckingStepImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Provider<OtpCheckingAdapter> otpCheck;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<AuthenticationMethod> authMethod;

      @SuppressFBWarnings(justification = "generated code")
      RadiusOtpCheckingStepImplBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public RadiusOtpCheckingStepImpl.RadiusOtpCheckingStepImplBuilder otpCheck(Provider<OtpCheckingAdapter> otpCheck) {
         this.otpCheck = otpCheck;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RadiusOtpCheckingStepImpl.RadiusOtpCheckingStepImplBuilder authMethod(Provider<AuthenticationMethod> authMethod) {
         this.authMethod = authMethod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RadiusOtpCheckingStepImpl build() {
         return new RadiusOtpCheckingStepImpl(this.otpCheck, this.authMethod);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "RadiusOtpCheckingStepImpl.RadiusOtpCheckingStepImplBuilder(otpCheck=" + this.otpCheck + ", authMethod=" + this.authMethod + ")";
      }
   }
}
