package com.airlock.iam.login.application.configuration.targetapp;

import com.airlock.iam.login.domain.model.targetapp.UserRoleWafCredentialProvider;
import com.airlock.iam.login.domain.model.targetapp.WafCredentialProviderTimeouts;
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.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.PropertyConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;
import java.util.regex.Pattern;

@Plugin(description = "Provides a Airlock Gateway role conditional on the presence of a user role.", displayName = "Role-based Gateway Role")
public final class UserRoleWafCredentialProviderConfig extends WafCredentialProviderTimeouts implements WafCredentialProviderConfig {
   @StringProperty(
      description = "The name of a user role. If the user has this role on the database / persistence layer, an Airlock Gateway role is added as follows: <ul><li>If the \"Gateway Mapping Role\" is not defined, the user role name is used as Airlock Gateway role. In this case, the role name must not include special characters.</li><li>Otherwise, the \"Gateway Mapping Role\" is used as Airlock Gateway role.</li></ul>",
      optional = false
   )
   private String userRoleName;
   private static final String USER_ROLE_NAME_FIELD = "userRoleName";
   @StringProperty(
      description = "The name can be defined in case a name different from the 'User Role Name' must be used. Please refer to the property description of 'User Role Name'.",
      displayName = "Gateway Mapping Role",
      optional = true,
      maxLength = 50,
      validationRegex = "[a-zA-Z0-9_.\\-]+"
   )
   private String wafCredentialName;
   private static final String WAF_CREDENTIAL_NAME_FIELD = "wafCredentialName";
   public static final String USER_ROLE_NAME_DISPLAY_NAME = "User Role Name";
   public static final String GATEWAY_MAPPING_ROLE_DISPLAY_NAME = "Gateway Mapping Role";

   private UserRoleWafCredentialProviderConfig(Integer idleTimeout, Integer lifetime, String wafCredentialName, String userRoleName) {
      super(idleTimeout, lifetime);
      this.wafCredentialName = wafCredentialName;
      this.userRoleName = userRoleName;
   }

   public UserRoleWafCredentialProvider.UserRoleWafCredentialProviderConfiguration getConfiguration() {
      return UserRoleWafCredentialProvider.UserRoleWafCredentialProviderConfiguration.builder(this.userRoleName)
         .idleTimeout(this.getIdleTimeout())
         .lifetime(this.getLifetime())
         .wafCredentialName(Optional.ofNullable(this.wafCredentialName))
         .build();
   }

   @ConfigurationValidator
   public static void validateUserRoleNameIfWafCredentialNameNotConfigured(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws PropertyConfigurationException {
      String configuredUserRole = StringPropertyValueReader.effectiveStringConfigValue(config, "userRoleName", env, context);
      String configuredWafCredential = StringPropertyValueReader.effectiveStringConfigValue(config, "wafCredentialName", env, context);
      if (configuredWafCredential == null && !Pattern.compile("[a-zA-Z0-9_.\\-]+").matcher(configuredUserRole).matches()) {
         throw new PropertyConstraintViolationException(
            "wafCredentialName",
            config,
            env,
            context,
            "The 'User Role Name' contains invalid characters. Please define a 'Gateway Mapping Role' or use a 'User Role Name' not containing special characters."
         );
      }
   }

   public String getUserRoleName() {
      return this.userRoleName;
   }

   public String getWafCredentialName() {
      return this.wafCredentialName;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class UserRoleWafCredentialProviderConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Integer idleTimeout;
      @SuppressFBWarnings(justification = "generated code")
      private Integer lifetime;
      @SuppressFBWarnings(justification = "generated code")
      private String wafCredentialName;
      @SuppressFBWarnings(justification = "generated code")
      private String userRoleName;

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

      @SuppressFBWarnings(justification = "generated code")
      public UserRoleWafCredentialProviderConfig.UserRoleWafCredentialProviderConfigBuilder idleTimeout(Integer idleTimeout) {
         this.idleTimeout = idleTimeout;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserRoleWafCredentialProviderConfig.UserRoleWafCredentialProviderConfigBuilder lifetime(Integer lifetime) {
         this.lifetime = lifetime;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserRoleWafCredentialProviderConfig.UserRoleWafCredentialProviderConfigBuilder wafCredentialName(String wafCredentialName) {
         this.wafCredentialName = wafCredentialName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserRoleWafCredentialProviderConfig.UserRoleWafCredentialProviderConfigBuilder userRoleName(String userRoleName) {
         this.userRoleName = userRoleName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserRoleWafCredentialProviderConfig build() {
         return new UserRoleWafCredentialProviderConfig(this.idleTimeout, this.lifetime, this.wafCredentialName, this.userRoleName);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "UserRoleWafCredentialProviderConfig.UserRoleWafCredentialProviderConfigBuilder(idleTimeout="
            + this.idleTimeout
            + ", lifetime="
            + this.lifetime
            + ", wafCredentialName="
            + this.wafCredentialName
            + ", userRoleName="
            + this.userRoleName
            + ")";
      }
   }
}
