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

import com.airlock.iam.core.misc.plugin.config.validation.UriPropertyValidator;
import com.airlock.iam.flow.shared.api.application.configuration.captcha.CaptchaProviderConfig;
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.property.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
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.ConfigurationException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;

@Plugin(
   displayName = "Custom CAPTCHA",
   description = "Requires a user to solve a custom CAPTCHA challenge.</br>\nIntended for use with a CAPTCHA Server that is API-compatible with reCAPTCHA. For reCAPTCHA and hCAPTCHA the according plugins should be used instead.</br>\nThis plugin configuration does not affect the Loginapp UI. You will need to adapt it with design kit customization."
)
@Groups(groupSequence = {"Basic Settings", "Proxy Settings"}, openGroups = "Basic Settings")
public final class CustomCaptchaConfig implements CaptchaProviderConfig {
   static final String PROXY_SETTINGS = "Proxy Settings";
   @StringProperty(description = "<p>The site key can be assumed to be public knowledge and identifies the associated CAPTCHA account.</p>", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String siteKey;
   @StringProperty(
      description = "<p>The secret is used to validate the CAPTCHA challenge response on the custom CAPTCHA server.</p>",
      isSensitive = true,
      optional = false
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String secretKey;
   @StringProperty(
      description = "URL of the CAPTCHA service to use. The CAPTCHA validation will be performed against a CAPTCHA server with this URL. The server API must match the reCAPTCHA API. <p>For example, the API request for reCAPTCHA is 'https://google.com/recaptcha/api/siteverify' as POST method with the 'secret' and the user 'response' token as POST parameters. </p>",
      displayName = "CAPTCHA Service URL",
      optional = false
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String captchaServiceUrl;
   private static final String CAPTCHA_SERVICE_URL_FIELD = "captchaServiceUrl";
   private static final String CAPTCHA_SERVICE_URL_DISPLAY_NAME = "CAPTCHA Service URL";
   @BooleanProperty(
      description = "Whether a CAPTCHA solution is always required. By default, solving a CAPTCHA in a step will cause subsequent steps with CAPTCHA to skip CAPTCHA verification. When this setting is enabled, the user is always required to solve the CAPTCHA for this step, irrespective of whether a CAPTCHA has previously been solved. Later CAPTCHA verifications are also not influenced by the step using this CAPTCHA, i.e. solving the CAPTCHA in this step has no effect on later CAPTCHA verifications. When this setting is disabled, no CAPTCHA is required if a CAPTCHA was resolved in a preceding step, unless the preceding Custom Captcha Step had this setting activated.",
      displayName = "Enforce CAPTCHA for step",
      optional = true,
      defaultValue = "false"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private boolean enforceCaptchaForStep;
   @StringProperty(
      description = "The type is used to differentiate multiple types of CAPTCHA (reCAPTCHA, hCAPTCHA or multiple custom CAPTCHA). If you use multiple custom CAPTCHA make sure this type is unique. ",
      optional = true,
      defaultValue = "CUSTOM_CAPTCHA"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String type;
   @StringProperty(
      description = "URI of a HTTP proxy the connector should use. If the port component of the URI is absent then a default port of 8080 is assumed. If this property is left empty then no proxy will be used.",
      displayName = "Proxy URI",
      optional = true,
      exampleValues = "https://proxy.company.com"
   )
   @GroupProperty(groupIdentifier = "Proxy Settings")
   private String proxyUri;
   private static final String FIELD_PROXY_URI = "proxyUri";
   @StringProperty(description = "Username for the proxy if proxy authentication is used.", optional = true)
   @GroupProperty(groupIdentifier = "Proxy Settings")
   private String proxyLoginUser;
   @StringProperty(description = "Password for the proxy if proxy authentication is used.", optional = true, isSensitive = true)
   @GroupProperty(groupIdentifier = "Proxy Settings")
   private String proxyLoginPassword;

   @ConfigurationValidator
   static void checkCaptchaServiceUrl(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment) throws ConfigurationException {
      UriPropertyValidator.uriPropertyValidator("captchaServiceUrl", "CAPTCHA Service URL", config, env, context)
         .validateIsUri()
         .validateHasNoQuery()
         .validateHasNoFragment();
   }

   public String getSiteKey() {
      return this.siteKey;
   }

   public String getSecretKey() {
      return this.secretKey;
   }

   public String getCaptchaServiceUrl() {
      return this.captchaServiceUrl;
   }

   public boolean isEnforceCaptchaForStep() {
      return this.enforceCaptchaForStep;
   }

   public String getType() {
      return this.type;
   }

   @Nullable
   public String getProxyUri() {
      return this.proxyUri;
   }

   @Nullable
   public String getProxyLoginUser() {
      return this.proxyLoginUser;
   }

   @Nullable
   public String getProxyLoginPassword() {
      return this.proxyLoginPassword;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public CustomCaptchaConfig(
      String siteKey,
      String secretKey,
      String captchaServiceUrl,
      boolean enforceCaptchaForStep,
      String type,
      String proxyUri,
      String proxyLoginUser,
      String proxyLoginPassword
   ) {
      this.siteKey = siteKey;
      this.secretKey = secretKey;
      this.captchaServiceUrl = captchaServiceUrl;
      this.enforceCaptchaForStep = enforceCaptchaForStep;
      this.type = type;
      this.proxyUri = proxyUri;
      this.proxyLoginUser = proxyLoginUser;
      this.proxyLoginPassword = proxyLoginPassword;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class CustomCaptchaConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String siteKey;
      @SuppressFBWarnings(justification = "generated code")
      private String secretKey;
      @SuppressFBWarnings(justification = "generated code")
      private String captchaServiceUrl;
      @SuppressFBWarnings(justification = "generated code")
      private boolean enforceCaptchaForStep;
      @SuppressFBWarnings(justification = "generated code")
      private String type;
      @SuppressFBWarnings(justification = "generated code")
      private String proxyUri;
      @SuppressFBWarnings(justification = "generated code")
      private String proxyLoginUser;
      @SuppressFBWarnings(justification = "generated code")
      private String proxyLoginPassword;

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

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig.CustomCaptchaConfigBuilder siteKey(String siteKey) {
         this.siteKey = siteKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig.CustomCaptchaConfigBuilder secretKey(String secretKey) {
         this.secretKey = secretKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig.CustomCaptchaConfigBuilder captchaServiceUrl(String captchaServiceUrl) {
         this.captchaServiceUrl = captchaServiceUrl;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig.CustomCaptchaConfigBuilder enforceCaptchaForStep(boolean enforceCaptchaForStep) {
         this.enforceCaptchaForStep = enforceCaptchaForStep;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig.CustomCaptchaConfigBuilder type(String type) {
         this.type = type;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig.CustomCaptchaConfigBuilder proxyUri(String proxyUri) {
         this.proxyUri = proxyUri;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig.CustomCaptchaConfigBuilder proxyLoginUser(String proxyLoginUser) {
         this.proxyLoginUser = proxyLoginUser;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig.CustomCaptchaConfigBuilder proxyLoginPassword(String proxyLoginPassword) {
         this.proxyLoginPassword = proxyLoginPassword;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CustomCaptchaConfig build() {
         return new CustomCaptchaConfig(
            this.siteKey,
            this.secretKey,
            this.captchaServiceUrl,
            this.enforceCaptchaForStep,
            this.type,
            this.proxyUri,
            this.proxyLoginUser,
            this.proxyLoginPassword
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "CustomCaptchaConfig.CustomCaptchaConfigBuilder(siteKey="
            + this.siteKey
            + ", secretKey="
            + this.secretKey
            + ", captchaServiceUrl="
            + this.captchaServiceUrl
            + ", enforceCaptchaForStep="
            + this.enforceCaptchaForStep
            + ", type="
            + this.type
            + ", proxyUri="
            + this.proxyUri
            + ", proxyLoginUser="
            + this.proxyLoginUser
            + ", proxyLoginPassword="
            + this.proxyLoginPassword
            + ")";
      }
   }
}
