package com.airlock.iam.login.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.ExtendedStringGenerator;
import com.airlock.iam.plugin.api.annotation.config.DeprecatedPlugin;
import com.airlock.iam.plugin.api.annotation.config.Groups;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.property.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.IntegerProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.annotation.property.RegexProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.time.Duration;
import java.util.Optional;
import java.util.regex.Pattern;

@Plugin(description = "The settings for managing mTAN tokens.", displayName = "mTAN Self-Services (Legacy)")
@DeprecatedPlugin(
   description = "The session-less mTAN self-service endpoints are deprecated and will be removed in a future IAM version. Use protected self-service flows instead."
)
@Groups(groupSequence = {"Basic Settings", "Number Change"}, openGroups = {"Basic Settings", "Number Change"})
public class MtanSelfServicesLegacyConfig implements MtanSelfManagementConfig {
   static final String NUMBER_CHANGE = "Number Change";
   @PluginProperty(description = "General settings for SMS/mTAN handling.", optional = false, displayName = "mTAN Settings")
   @GroupProperty(groupIdentifier = "Basic Settings")
   private BasicMtanSettings mtanSettings;
   @StringProperty(
      description = "Key of the message template in the string resource files to enable language-specific messages to be sent to the user. The string <code>$TOKEN$</code> in the message template is mandatory and is replaced by the token.",
      optional = true,
      defaultValue = "sms-authenticator.default-message"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String messageTemplateKey;
   @PluginProperty(
      description = "The string generator plugin to generate the one time password (OTP) token.",
      displayName = "OTP Generator",
      optional = true,
      defaultValue = ExtendedStringGenerator.class
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private SecretStringGenerator tokenGenerator;
   @BooleanProperty(
      description = "If enabled, the case of characters is respected when checking OTP tokens.",
      defaultValue = "true",
      optional = true,
      displayName = "Case-Sensitive OTP Check"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private boolean otpCaseSensitive;
   @BooleanProperty(
      description = "If enabled, the user may change an already registered mobile phone number by starting the registration process for mobile phone numbers. If disabled (the default), changing an already registered number is not possible.",
      optional = true,
      defaultValue = "false"
   )
   @GroupProperty(groupIdentifier = "Number Change")
   private boolean allowPhoneNumberChange;
   @IntegerProperty(
      description = "Determines how long the OTP is valid (in seconds).",
      displayName = "OTP Validity [s]",
      exampleValues = {60, 300, 600},
      minValue = 1,
      defaultValue = 300,
      optional = true
   )
   @GroupProperty(groupIdentifier = "Number Change")
   private int otpValidity;
   @RegexProperty(
      description = "Regular expression to restrict phone numbers (e.g. to a specific country or internal company numbers).<br/>If configured, the <em>normalized</em> phone number is matched against this regular expression.",
      displayName = "Normalized Number Validation Regex",
      exampleValues = "^\\+41.*",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Number Change")
   private Pattern phoneNumberValidationRegex;

   @Override
   public Optional<PhoneNumberChangeSettings> getPhoneNumberChangeSettings() {
      if (!this.allowPhoneNumberChange) {
         return Optional.empty();
      }

      Duration validity = Duration.ofSeconds(this.otpValidity);
      return Optional.of(new PhoneNumberChangeSettings(validity, Optional.ofNullable(this.phoneNumberValidationRegex)));
   }

   @Override
   public BasicMtanSettings getMtanSettings() {
      return this.mtanSettings;
   }

   @Override
   public String getMessageTemplateKey() {
      return this.messageTemplateKey;
   }

   @Override
   public SecretStringGenerator getTokenGenerator() {
      return this.tokenGenerator;
   }

   @Override
   public boolean isOtpCaseSensitive() {
      return this.otpCaseSensitive;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public MtanSelfServicesLegacyConfig(
      BasicMtanSettings mtanSettings,
      String messageTemplateKey,
      SecretStringGenerator tokenGenerator,
      boolean otpCaseSensitive,
      boolean allowPhoneNumberChange,
      int otpValidity,
      Pattern phoneNumberValidationRegex
   ) {
      this.mtanSettings = mtanSettings;
      this.messageTemplateKey = messageTemplateKey;
      this.tokenGenerator = tokenGenerator;
      this.otpCaseSensitive = otpCaseSensitive;
      this.allowPhoneNumberChange = allowPhoneNumberChange;
      this.otpValidity = otpValidity;
      this.phoneNumberValidationRegex = phoneNumberValidationRegex;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class MtanSelfServicesLegacyConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private BasicMtanSettings mtanSettings;
      @SuppressFBWarnings(justification = "generated code")
      private String messageTemplateKey;
      @SuppressFBWarnings(justification = "generated code")
      private SecretStringGenerator tokenGenerator;
      @SuppressFBWarnings(justification = "generated code")
      private boolean otpCaseSensitive;
      @SuppressFBWarnings(justification = "generated code")
      private boolean allowPhoneNumberChange;
      @SuppressFBWarnings(justification = "generated code")
      private int otpValidity;
      @SuppressFBWarnings(justification = "generated code")
      private Pattern phoneNumberValidationRegex;

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

      @SuppressFBWarnings(justification = "generated code")
      public MtanSelfServicesLegacyConfig.MtanSelfServicesLegacyConfigBuilder mtanSettings(BasicMtanSettings mtanSettings) {
         this.mtanSettings = mtanSettings;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanSelfServicesLegacyConfig.MtanSelfServicesLegacyConfigBuilder messageTemplateKey(String messageTemplateKey) {
         this.messageTemplateKey = messageTemplateKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanSelfServicesLegacyConfig.MtanSelfServicesLegacyConfigBuilder tokenGenerator(SecretStringGenerator tokenGenerator) {
         this.tokenGenerator = tokenGenerator;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanSelfServicesLegacyConfig.MtanSelfServicesLegacyConfigBuilder otpCaseSensitive(boolean otpCaseSensitive) {
         this.otpCaseSensitive = otpCaseSensitive;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanSelfServicesLegacyConfig.MtanSelfServicesLegacyConfigBuilder allowPhoneNumberChange(boolean allowPhoneNumberChange) {
         this.allowPhoneNumberChange = allowPhoneNumberChange;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanSelfServicesLegacyConfig.MtanSelfServicesLegacyConfigBuilder otpValidity(int otpValidity) {
         this.otpValidity = otpValidity;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanSelfServicesLegacyConfig.MtanSelfServicesLegacyConfigBuilder phoneNumberValidationRegex(Pattern phoneNumberValidationRegex) {
         this.phoneNumberValidationRegex = phoneNumberValidationRegex;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanSelfServicesLegacyConfig build() {
         return new MtanSelfServicesLegacyConfig(
            this.mtanSettings,
            this.messageTemplateKey,
            this.tokenGenerator,
            this.otpCaseSensitive,
            this.allowPhoneNumberChange,
            this.otpValidity,
            this.phoneNumberValidationRegex
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "MtanSelfServicesLegacyConfig.MtanSelfServicesLegacyConfigBuilder(mtanSettings="
            + this.mtanSettings
            + ", messageTemplateKey="
            + this.messageTemplateKey
            + ", tokenGenerator="
            + this.tokenGenerator
            + ", otpCaseSensitive="
            + this.otpCaseSensitive
            + ", allowPhoneNumberChange="
            + this.allowPhoneNumberChange
            + ", otpValidity="
            + this.otpValidity
            + ", phoneNumberValidationRegex="
            + this.phoneNumberValidationRegex
            + ")";
      }
   }
}
