package com.airlock.iam.login.rest.application.configuration.ui;

import com.airlock.iam.authentication.application.configuration.ui.AuthenticationUiConfigs;
import com.airlock.iam.flow.shared.application.configuration.uitenantid.UiTenantIdRuleConfig;
import com.airlock.iam.login.application.configuration.uiresource.UiResourceSetRuleConfig;
import com.airlock.iam.login.rest.application.configuration.LoginRestUiContentSecurityPolicy;
import com.airlock.iam.login.rest.application.configuration.LoginappUiContentSecurityPolicyConfig;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
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.license.PluginPropertyLicenseRestriction;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginListProperty;
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.publicselfservice.application.configuration.ui.PublicSelfServiceUiConfigs;
import com.airlock.iam.selfservice.application.configuration.ui.SelfServiceUiConfigs;
import com.airlock.iam.userselfreg.application.configuration.ui.UserSelfRegUiConfigs;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.List;
import java.util.Optional;

@Plugin(description = "User interface configuration for Loginapp REST API.", displayName = "UI Settings")
@Groups(groupSequence = {"Basic Settings", "Security Settings"}, openGroups = "Basic Settings")
public final class LoginappUiConfig {
   public static final String CSP_WAF_COMPATIBILITY_NOTE = "<p>The Airlock Gateway (WAF) \"CSRF Tokens\" feature does not support CSP nonces before Gateway version 7.3. We recommend updating to Airlock Gateway 7.3 or higher and enabling both the CSP features on IAM and the \"CSRF Tokens\" feature on the mapping for IAM. If an update to Airlock Gateway 7.3 is currently not possible, we recommend temporarily disabling the Gateway \"CSRF Tokens\" feature and re-enabling it after the update.</p>";
   @PluginProperty(description = "Allows to configure the user interfaces for authentication flows.", displayName = "Authentication UIs", optional = true)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private AuthenticationUiConfigs authenticationUi;
   public static final String AUTH_UI_CONFIGS_PROPERTY = "authenticationUi";
   @PluginProperty(
      description = "Allows to configure the user interfaces for user self-registration flows.",
      displayName = "User Self-Registration UIs",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   @PluginPropertyLicenseRestriction(moduleAffiliation = "SelfRegistration")
   private UserSelfRegUiConfigs userSelfRegUi;
   public static final String SELF_REG_UI_CONFIGS_PROPERTY = "userSelfRegUi";
   @PluginProperty(description = "Allows to configure the user interfaces for public self-services.", displayName = "Public Self-Service UIs", optional = true)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private PublicSelfServiceUiConfigs publicSelfServiceUi;
   public static final String PUBLIC_SELF_SERVICE_UI_CONFIG_PROPERTY = "publicSelfServiceUi";
   @PluginProperty(
      description = "Allows to configure the user interfaces for protected self-services.",
      displayName = "Protected Self-Service UIs",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private SelfServiceUiConfigs selfServiceUi;
   public static final String SELF_SERVICE_UI_CONFIG_PROPERTY = "selfServiceUi";
   @PluginProperty(
      description = "<p>Content Security Policy (CSP) for the Loginapp UI.</p><p>The Airlock Gateway (WAF) \"CSRF Tokens\" feature does not support CSP nonces before Gateway version 7.3. We recommend updating to Airlock Gateway 7.3 or higher and enabling both the CSP features on IAM and the \"CSRF Tokens\" feature on the mapping for IAM. If an update to Airlock Gateway 7.3 is currently not possible, we recommend temporarily disabling the Gateway \"CSRF Tokens\" feature and re-enabling it after the update.</p>",
      displayName = "Loginapp UI Content Security Policy (CSP)",
      defaultValue = LoginappUiContentSecurityPolicyConfig.class,
      optional = true
   )
   @GroupProperty(groupIdentifier = "Security Settings")
   private LoginRestUiContentSecurityPolicy loginRestUiContentSecurityPolicy;
   @PluginListProperty(
      displayName = "UI Tenant ID Rules",
      description = "<p>Define rules to set the UI Tenant ID.</p>\n<p>Changing the UI Tenant ID allows defining custom behavior inside a single Loginapp Design Kit customization.</p>\n<p>The rules are evaluated in the order in which they are configured, and the first rule that is satisfied is\nused to set the value of the UI Tenant ID. If no rule is satisfied (or if no rule is configured),\nthe UI Tenant ID is not set.</p>\n<p>The rules configured here are shared across all flow UI types.</p>",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private List<UiTenantIdRuleConfig> uiTenantIdRules;
   @PluginListProperty(
      displayName = "UI Resource Set Rules",
      description = "<p>Defines rules to dynamically change the UI resource set to the specified customization.</p>\n<p>This property permits dynamically changing the directory from which UI resources are loaded,\nbased on the first matching rule.</p>\n<p>The UI resource set zip files have to be located in a directory specified in the instance.properties under\n<tt>iam.loginapp.ui.resource-sets.dir</tt>.</p>\n<p>The zip files must have unique file names, otherwise the contained resources will not be available.</p>\n<p>The rules are evaluated in the order they are configured, and the first rule that is satisfied\nis used to set the path from which the resource is loaded.</p>\n<p>If no rule is satisfied (or if no rules are configured), the UI resources located at\n<tt>iam.loginapp.rest.ui.customizations</tt> are used, if configured. Otherwise, the default UI resources are used.</p>",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private List<UiResourceSetRuleConfig> uiResourceSetRules;

   public Optional<AuthenticationUiConfigs> getAuthenticationUis() {
      return Optional.ofNullable(this.authenticationUi);
   }

   public Optional<UserSelfRegUiConfigs> getUserSelfRegUis() {
      return Optional.ofNullable(this.userSelfRegUi);
   }

   public Optional<PublicSelfServiceUiConfigs> getPublicSelfServiceUis() {
      return Optional.ofNullable(this.publicSelfServiceUi);
   }

   public Optional<SelfServiceUiConfigs> getSelfServiceUis() {
      return Optional.ofNullable(this.selfServiceUi);
   }

   public List<UiTenantIdRuleConfig> getUiTenantIdRules() {
      return this.uiTenantIdRules;
   }

   public List<UiResourceSetRuleConfig> getUiResourceSetRules() {
      return this.uiResourceSetRules;
   }

   @ConfigurationValidator
   static void validateReferencedApplicationIds(
      PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      LoginRestUisConfigValidator validator = new LoginRestUisConfigValidator(pc, env, context);
      validator.validateReferencedApplicationId();
   }

   @ConfigurationValidator
   static void validateReferencedSelfRegFlowIds(
      PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      LoginRestUisConfigValidator validator = new LoginRestUisConfigValidator(pc, env, context);
      validator.validateReferencedSelfRegFlowId();
   }

   @ConfigurationValidator
   static void validateReferencedPublicSelfServiceFlowIds(
      PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      LoginRestUisConfigValidator validator = new LoginRestUisConfigValidator(pc, env, context);
      validator.validateReferencedPublicSelfServiceFlowId();
   }

   @ConfigurationValidator
   static void validateReferencedAdditionalAuthenticationFlowIds(
      PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      LoginRestUisConfigValidator validator = new LoginRestUisConfigValidator(pc, env, context);
      validator.validateReferencedAdditionalAuthenticationFlowIds();
   }

   public LoginRestUiContentSecurityPolicy getLoginRestUiContentSecurityPolicy() {
      return this.loginRestUiContentSecurityPolicy;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public LoginappUiConfig(
      AuthenticationUiConfigs authenticationUi,
      UserSelfRegUiConfigs userSelfRegUi,
      PublicSelfServiceUiConfigs publicSelfServiceUi,
      SelfServiceUiConfigs selfServiceUi,
      LoginRestUiContentSecurityPolicy loginRestUiContentSecurityPolicy,
      List<UiTenantIdRuleConfig> uiTenantIdRules,
      List<UiResourceSetRuleConfig> uiResourceSetRules
   ) {
      this.authenticationUi = authenticationUi;
      this.userSelfRegUi = userSelfRegUi;
      this.publicSelfServiceUi = publicSelfServiceUi;
      this.selfServiceUi = selfServiceUi;
      this.loginRestUiContentSecurityPolicy = loginRestUiContentSecurityPolicy;
      this.uiTenantIdRules = uiTenantIdRules;
      this.uiResourceSetRules = uiResourceSetRules;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class LoginappUiConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private AuthenticationUiConfigs authenticationUi;
      @SuppressFBWarnings(justification = "generated code")
      private UserSelfRegUiConfigs userSelfRegUi;
      @SuppressFBWarnings(justification = "generated code")
      private PublicSelfServiceUiConfigs publicSelfServiceUi;
      @SuppressFBWarnings(justification = "generated code")
      private SelfServiceUiConfigs selfServiceUi;
      @SuppressFBWarnings(justification = "generated code")
      private LoginRestUiContentSecurityPolicy loginRestUiContentSecurityPolicy;
      @SuppressFBWarnings(justification = "generated code")
      private List<UiTenantIdRuleConfig> uiTenantIdRules;
      @SuppressFBWarnings(justification = "generated code")
      private List<UiResourceSetRuleConfig> uiResourceSetRules;

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

      @SuppressFBWarnings(justification = "generated code")
      public LoginappUiConfig.LoginappUiConfigBuilder authenticationUi(AuthenticationUiConfigs authenticationUi) {
         this.authenticationUi = authenticationUi;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappUiConfig.LoginappUiConfigBuilder userSelfRegUi(UserSelfRegUiConfigs userSelfRegUi) {
         this.userSelfRegUi = userSelfRegUi;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappUiConfig.LoginappUiConfigBuilder publicSelfServiceUi(PublicSelfServiceUiConfigs publicSelfServiceUi) {
         this.publicSelfServiceUi = publicSelfServiceUi;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappUiConfig.LoginappUiConfigBuilder selfServiceUi(SelfServiceUiConfigs selfServiceUi) {
         this.selfServiceUi = selfServiceUi;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappUiConfig.LoginappUiConfigBuilder loginRestUiContentSecurityPolicy(LoginRestUiContentSecurityPolicy loginRestUiContentSecurityPolicy) {
         this.loginRestUiContentSecurityPolicy = loginRestUiContentSecurityPolicy;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappUiConfig.LoginappUiConfigBuilder uiTenantIdRules(List<UiTenantIdRuleConfig> uiTenantIdRules) {
         this.uiTenantIdRules = uiTenantIdRules;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappUiConfig.LoginappUiConfigBuilder uiResourceSetRules(List<UiResourceSetRuleConfig> uiResourceSetRules) {
         this.uiResourceSetRules = uiResourceSetRules;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappUiConfig build() {
         return new LoginappUiConfig(
            this.authenticationUi,
            this.userSelfRegUi,
            this.publicSelfServiceUi,
            this.selfServiceUi,
            this.loginRestUiContentSecurityPolicy,
            this.uiTenantIdRules,
            this.uiResourceSetRules
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "LoginappUiConfig.LoginappUiConfigBuilder(authenticationUi="
            + this.authenticationUi
            + ", userSelfRegUi="
            + this.userSelfRegUi
            + ", publicSelfServiceUi="
            + this.publicSelfServiceUi
            + ", selfServiceUi="
            + this.selfServiceUi
            + ", loginRestUiContentSecurityPolicy="
            + this.loginRestUiContentSecurityPolicy
            + ", uiTenantIdRules="
            + this.uiTenantIdRules
            + ", uiResourceSetRules="
            + this.uiResourceSetRules
            + ")";
      }
   }
}
