package com.airlock.iam.flow.shared.application.configuration.mtan;

import com.airlock.iam.common.application.configuration.mtan.BasicMtanSettings;
import com.airlock.iam.core.misc.authen.SecretStringGenerator;
import com.airlock.iam.core.misc.impl.authen.mtan.MtanSettings;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.lifecycle.AfterConfigActivation;
import com.airlock.iam.plugin.api.annotation.property.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.BooleanPropertyValueReader;
import com.airlock.iam.plugin.framework.application.service.builder.plugin.PluginPropertyBuilderInitializer;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.time.Duration;

@Plugin(
   description = "The settings for mTAN OTP checks based on the existing \"MTAN/SMS Settings\".",
   displayName = "mTAN OTP Check Settings (based on mTAN Settings)"
)
public final class ExistingMtanOtpCheckConfig implements MtanOtpCheckConfigSpec {
   private static final String CHOOSE_LAST_NUMBER_AUTOMATICALLY_DISPLAY_NAME = "Choose Last Number Automatically";
   private static final String AUTO_SELECT_SINGLE_NUMBER_DISPLAY_NAME = "Auto Select Single Number";
   @PluginProperty(
      description = "Defines all settings for mTAN.",
      displayName = "mTAN Settings",
      globalPluginReference = "globalMtanSettings",
      optional = false
   )
   private MtanSettings mtanSettings;
   @BooleanProperty(
      description = "If enabled, the number used for the last successful login attempt is chosen automatically without any user interaction.",
      displayName = "Choose Last Number Automatically",
      optional = true,
      defaultValue = "false"
   )
   private boolean chooseLastNumberAutomatically;
   static final String CHOOSE_LAST_NUMBER_AUTOMATICALLY = "chooseLastNumberAutomatically";
   @BooleanProperty(
      description = "Controls whether the verification starts automatically or if a single number choice is presented as a selection to the client.",
      displayName = "Auto Select Single Number",
      defaultValue = "true",
      optional = true
   )
   private boolean autoSelectSingleNumber;
   static final String AUTO_SELECT_SINGLE_NUMBER = "autoSelectSingleNumber";
   private BasicMtanSettings initializedBasicMtanSettings;

   public ExistingMtanOtpCheckConfig(MtanSettings mtanSettings, boolean chooseLastNumberAutomatically, boolean autoSelectSingleNumber) {
      this.mtanSettings = mtanSettings;
      this.chooseLastNumberAutomatically = chooseLastNumberAutomatically;
      this.autoSelectSingleNumber = autoSelectSingleNumber;
   }

   @Override
   public boolean isResendSameOtp() {
      return this.mtanSettings.isRetransmitSameToken();
   }

   @Override
   public int getMaxWrongOtpChecks() {
      return this.mtanSettings.getMaxTokenRetries();
   }

   @Override
   public int getMaxOtpResends() {
      return this.mtanSettings.getMaxTokenRetransmissions();
   }

   @Override
   public Duration getOtpValidity() {
      return this.mtanSettings.getOtpValidity();
   }

   @Override
   public boolean isLastTokenAutomaticallySelected() {
      return this.chooseLastNumberAutomatically;
   }

   @Override
   public SecretStringGenerator getOtpGenerator() {
      return this.mtanSettings.getOtpGenerator();
   }

   @Override
   public boolean isOtpCaseSensitive() {
      return !this.mtanSettings.isIgnoreTokenCase();
   }

   @ConfigurationValidator
   static void checkOptionsForSingleNumbers(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      boolean autoSelectSingleNumber = BooleanPropertyValueReader.effectiveBooleanPropertyValue(config, "autoSelectSingleNumber", env, context);
      boolean chooseLastNumberAutomatically = BooleanPropertyValueReader.effectiveBooleanPropertyValue(config, "chooseLastNumberAutomatically", env, context);
      if (!autoSelectSingleNumber && chooseLastNumberAutomatically) {
         throw new PropertyConstraintViolationException(
            "autoSelectSingleNumber",
            config,
            env,
            context,
            "It is not possible to disable '%s' if '%s' is enabled.".formatted("Auto Select Single Number", "Choose Last Number Automatically")
         );
      }
   }

   @AfterConfigActivation
   void initializeBasicSettings() {
      this.initializedBasicMtanSettings = ((BasicMtanSettings.BasicMtanSettingsBuilder)PluginPropertyBuilderInitializer.pluginBuilder(
            BasicMtanSettings.BasicMtanSettingsBuilder.class
         ))
         .mtanHandler(this.mtanSettings.getMtanHandler())
         .smsGateway(this.mtanSettings.getSmsGateway())
         .originator(this.mtanSettings.getOriginatorName())
         .defaultCountryCode(this.mtanSettings.getDefaultCountryCode().getCode())
         .useFlashMessages(this.mtanSettings.isUseFlashMessages())
         .visiblePhoneNumberDigits(this.mtanSettings.getVisiblePhoneNumberDigits())
         .build();
   }

   @Override
   public BasicMtanSettings getBasicSettings() {
      return this.initializedBasicMtanSettings;
   }

   public MtanSettings getMtanSettings() {
      return this.mtanSettings;
   }

   @Override
   public boolean isAutoSelectSingleNumber() {
      return this.autoSelectSingleNumber;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public ExistingMtanOtpCheckConfig() {
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class ExistingMtanOtpCheckConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private MtanSettings mtanSettings;
      @SuppressFBWarnings(justification = "generated code")
      private boolean chooseLastNumberAutomatically;
      @SuppressFBWarnings(justification = "generated code")
      private boolean autoSelectSingleNumber;

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

      @SuppressFBWarnings(justification = "generated code")
      public ExistingMtanOtpCheckConfig.ExistingMtanOtpCheckConfigBuilder mtanSettings(MtanSettings mtanSettings) {
         this.mtanSettings = mtanSettings;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExistingMtanOtpCheckConfig.ExistingMtanOtpCheckConfigBuilder chooseLastNumberAutomatically(boolean chooseLastNumberAutomatically) {
         this.chooseLastNumberAutomatically = chooseLastNumberAutomatically;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExistingMtanOtpCheckConfig.ExistingMtanOtpCheckConfigBuilder autoSelectSingleNumber(boolean autoSelectSingleNumber) {
         this.autoSelectSingleNumber = autoSelectSingleNumber;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExistingMtanOtpCheckConfig build() {
         return new ExistingMtanOtpCheckConfig(this.mtanSettings, this.chooseLastNumberAutomatically, this.autoSelectSingleNumber);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "ExistingMtanOtpCheckConfig.ExistingMtanOtpCheckConfigBuilder(mtanSettings="
            + this.mtanSettings
            + ", chooseLastNumberAutomatically="
            + this.chooseLastNumberAutomatically
            + ", autoSelectSingleNumber="
            + this.autoSelectSingleNumber
            + ")";
      }
   }
}
