package com.airlock.iam.common.application.configuration.mtan;

import com.airlock.iam.base.api.domain.model.validation.ValidationResult;
import com.airlock.iam.common.domain.model.phone.VisiblePhoneNumberDigits;
import com.airlock.iam.core.domain.model.phone.CountryCallingCode;
import com.airlock.iam.core.domain.model.sms.validation.OriginatorValidator;
import com.airlock.iam.core.misc.impl.authen.mtan.MtanHandler;
import com.airlock.iam.core.misc.sms.SmsGateway;
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.property.BooleanProperty;
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.StringProperty;
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.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.exception.PropertyTypeMismatchException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang3.Strings;

@Plugin(description = "The basic settings for mTAN.", displayName = "Basic mTAN Settings")
public final class BasicMtanSettings {
   @PluginProperty(description = "An mTAN handler retrieves and updates mTAN number tokens.", optional = false, displayName = "mTAN Handler")
   private MtanHandler mtanHandler;
   public static final String MTAN_HANDLER_PROPERTY_NAME = "mtanHandler";
   @PluginProperty(description = "The SMS gateway used to send messages.", displayName = "SMS Gateway", optional = false)
   private SmsGateway smsGateway;
   @StringProperty(
      description = "<p>Originator of the SMS messages.</p>\n<p>There may be restrictions on the originator imposed by the SMS gateway service and by local law.</p>\n<p>The format of the originator must be one of:</p>\n<ul>\n  <li>Numeric characters only, optionally prefixed with a plus sign '+', at most 16 characters</li>\n  <li>Alphanumeric characters, at most 11 characters</li>\n</ul>\nFurthermore, the characters that are allowed may depend on your SMS gateway provider.",
      optional = false,
      exampleValues = "Airlock"
   )
   private String originator;
   private static final String ORIGINATOR_FIELD = "originator";
   @StringProperty(
      description = "Default country code to be used if a phone number does not contain a country code. It is only used when sending messages to the user.",
      minLength = 1,
      maxLength = 3,
      suggestedValues = {"41", "39", "49", "423"},
      optional = true,
      defaultValue = "41"
   )
   private String defaultCountryCode;
   @BooleanProperty(
      description = "<p>If enabled, SMS messages are sent as flash SMS by default. A flash message is\nshown directly on the mobile phone display.</p>\n<p>If the per-user setting is set, it takes precedence as long as a value\nis set for a user. If it is empty or not set, this default value is used.</p>\n<p><b>Note:</b> This has to be supported by the SMS gateway. Some recipients\nmight not be able to receive flash messages.</p>",
      optional = true,
      defaultValue = "false"
   )
   private boolean useFlashMessages;
   @IntegerProperty(
      description = "<p>Defines the number of phone number digits visible in log statements and in selection options sent to the user.</p>\n<p>If the value is zero, all digits are masked, if it is large enough, all digits are visible.\nExample: if set to 3, logged number looks like ********965.</p>\n<p>The default is 100, i.e. showing all digits.</p>",
      optional = true,
      defaultValue = 100,
      minValue = 0,
      exampleValues = {0, 3, 100}
   )
   private int visiblePhoneNumberDigits;

   public CountryCallingCode getDefaultCountryCode() {
      String normalizedDefaultCountryCode = Strings.CS.removeStart(this.defaultCountryCode, "+");
      return CountryCallingCode.of(normalizedDefaultCountryCode);
   }

   public VisiblePhoneNumberDigits getVisiblePhoneNumberDigits() {
      return VisiblePhoneNumberDigits.of(this.visiblePhoneNumberDigits);
   }

   @ConfigurationValidator
   public static void validateOriginator(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws PropertyTypeMismatchException, PropertyConstraintViolationException {
      String originator = StringPropertyValueReader.effectiveStringConfigValue(config, "originator", env, context);
      ValidationResult result = OriginatorValidator.defaultValidator().validate(originator);
      if (!result.isValid()) {
         throw new PropertyConstraintViolationException("originator", config, env, context, "Originator has no valid format: " + result.getFailure());
      }
   }

   public MtanHandler getMtanHandler() {
      return this.mtanHandler;
   }

   public SmsGateway getSmsGateway() {
      return this.smsGateway;
   }

   public String getOriginator() {
      return this.originator;
   }

   public boolean isUseFlashMessages() {
      return this.useFlashMessages;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public BasicMtanSettings(
      MtanHandler mtanHandler, SmsGateway smsGateway, String originator, String defaultCountryCode, boolean useFlashMessages, int visiblePhoneNumberDigits
   ) {
      this.mtanHandler = mtanHandler;
      this.smsGateway = smsGateway;
      this.originator = originator;
      this.defaultCountryCode = defaultCountryCode;
      this.useFlashMessages = useFlashMessages;
      this.visiblePhoneNumberDigits = visiblePhoneNumberDigits;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class BasicMtanSettingsBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private MtanHandler mtanHandler;
      @SuppressFBWarnings(justification = "generated code")
      private SmsGateway smsGateway;
      @SuppressFBWarnings(justification = "generated code")
      private String originator;
      @SuppressFBWarnings(justification = "generated code")
      private String defaultCountryCode;
      @SuppressFBWarnings(justification = "generated code")
      private boolean useFlashMessages;
      @SuppressFBWarnings(justification = "generated code")
      private int visiblePhoneNumberDigits;

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

      @SuppressFBWarnings(justification = "generated code")
      public BasicMtanSettings.BasicMtanSettingsBuilder mtanHandler(MtanHandler mtanHandler) {
         this.mtanHandler = mtanHandler;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public BasicMtanSettings.BasicMtanSettingsBuilder smsGateway(SmsGateway smsGateway) {
         this.smsGateway = smsGateway;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public BasicMtanSettings.BasicMtanSettingsBuilder originator(String originator) {
         this.originator = originator;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public BasicMtanSettings.BasicMtanSettingsBuilder defaultCountryCode(String defaultCountryCode) {
         this.defaultCountryCode = defaultCountryCode;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public BasicMtanSettings.BasicMtanSettingsBuilder useFlashMessages(boolean useFlashMessages) {
         this.useFlashMessages = useFlashMessages;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public BasicMtanSettings.BasicMtanSettingsBuilder visiblePhoneNumberDigits(int visiblePhoneNumberDigits) {
         this.visiblePhoneNumberDigits = visiblePhoneNumberDigits;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public BasicMtanSettings build() {
         return new BasicMtanSettings(
            this.mtanHandler, this.smsGateway, this.originator, this.defaultCountryCode, this.useFlashMessages, this.visiblePhoneNumberDigits
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "BasicMtanSettings.BasicMtanSettingsBuilder(mtanHandler="
            + this.mtanHandler
            + ", smsGateway="
            + this.smsGateway
            + ", originator="
            + this.originator
            + ", defaultCountryCode="
            + this.defaultCountryCode
            + ", useFlashMessages="
            + this.useFlashMessages
            + ", visiblePhoneNumberDigits="
            + this.visiblePhoneNumberDigits
            + ")";
      }
   }
}
