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

import com.airlock.iam.core.misc.persistency.CredentialPersister;
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.lifecycle.AfterConfigActivation;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
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.ConfigurationException;
import com.airlock.iam.plugin.framework.domain.service.validation.DurationParser;
import com.airlock.iam.plugin.framework.domain.service.validation.DurationValidator;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.time.Duration;
import java.util.Optional;

@Plugin(
   description = "<p>Configuration for the legacy implementation for Remember-Me using the JSP Loginapp.</p><p>This plugin is only needed for:<ul><li>Migrating legacy cookies during an authentication flow.</li><li>Displaying and deleting legacy cookies in the Adminapp user management.</li></ul></p>",
   displayName = "JSP Remember-Me Settings"
)
@Groups(groupSequence = {"Basic Settings", "Advanced Settings"}, openGroups = "Basic Settings")
public class JspRememberMeConfig {
   public static final String ENTRYPATH = "%ENTRYPATH%";
   @StringProperty(
      description = "The maximum lifetime of the cookie. After this time, the cookie will be invalidated no matter whether it has been used recently or not.<p>Duration must be specified like \"2d 4h 10m 5s\" or any part thereof.</p>",
      optional = true,
      defaultValue = "7d",
      exampleValues = {"10d", "8h", "2d 12h"}
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String cookieLifetime;
   private static final String COOKIE_LIFETIME_FIELD = "cookieLifetime";
   @StringProperty(
      description = "The optional idle timeout of the cookie. If a cookie hasn't been used for this amount of time, it will be invalidated no matter whether it has reached its lifetime or not. When this property is not set, every cookie will only expire when its lifetime has been reached or it has been invalidated by other means.<p>Duration must be specified like \"2d 4h 10m 5s\" or any part thereof.</p>",
      optional = true,
      exampleValues = {"10d", "8h", "2d 12h"}
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String cookieIdleTimeout;
   private static final String COOKIE_IDLE_TIMEOUT_FIELD = "cookieIdleTimeout";
   @PluginProperty(description = "Credential persister plugin used to load and store the cookie secrets.", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private CredentialPersister credentialPersister;
   @StringProperty(
      description = "The name of the Remember-Me cookie.<p>If this name is changed, the Airlock Gateway has to be reconfigured to pass-through and encrypt this cookie.</p>",
      exampleValues = "RememberMe",
      optional = true,
      defaultValue = "RememberMe"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private String cookieName;
   @StringProperty(
      description = "The domain for which the cookie is set. If left empty, it will be automatically be sent back only to the originating domain which set the cookie in the first place.",
      exampleValues = {"www.airlock.com", "airlock.com"},
      optional = true
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private String cookieDomain;
   @StringProperty(
      description = "The path for which the cookie is set. The path determines where the cookie is sent to by the browser.<p>Use the variable \"%ENTRYPATH%\" to automatically set the correct path even if used behind an Airlock Gateway.</p>",
      exampleValues = {"%ENTRYPATH%", "/", "/auth"},
      optional = true,
      defaultValue = "%ENTRYPATH%"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private String cookiePath;
   private Duration cookieLifetimeDuration;
   private Optional<Duration> cookieIdleTimeoutDuration;

   public JspRememberMeConfig(
      String cookieLifetime, String cookieIdleTimeout, CredentialPersister credentialPersister, String cookieName, String cookieDomain, String cookiePath
   ) {
      this.cookieLifetime = cookieLifetime;
      this.cookieIdleTimeout = cookieIdleTimeout;
      this.credentialPersister = credentialPersister;
      this.cookieName = cookieName;
      this.cookieDomain = cookieDomain;
      this.cookiePath = cookiePath;
   }

   @ConfigurationValidator
   public static void checkCookieTimeouts(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      DurationValidator.validateDurationFieldIfSet(config, "cookieLifetime", env, context);
      DurationValidator.validateDurationFieldIfSet(config, "cookieIdleTimeout", env, context);
   }

   @AfterConfigActivation
   void parseCookieTimeouts() {
      this.cookieLifetimeDuration = new DurationParser(this.cookieLifetime).getDuration();
      if (this.cookieIdleTimeout == null) {
         this.cookieIdleTimeoutDuration = Optional.empty();
      } else {
         this.cookieIdleTimeoutDuration = Optional.of(new DurationParser(this.cookieIdleTimeout).getDuration());
      }
   }

   public String getCookiePath(String currentFrontendPath) {
      return "%ENTRYPATH%".equals(this.cookiePath) ? currentFrontendPath : this.cookiePath;
   }

   public CredentialPersister getCredentialPersister() {
      return this.credentialPersister;
   }

   public String getCookieName() {
      return this.cookieName;
   }

   @Nullable
   public String getCookieDomain() {
      return this.cookieDomain;
   }

   public Duration getCookieLifetimeDuration() {
      return this.cookieLifetimeDuration;
   }

   public Optional<Duration> getCookieIdleTimeoutDuration() {
      return this.cookieIdleTimeoutDuration;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class JspRememberMeConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String cookieLifetime;
      @SuppressFBWarnings(justification = "generated code")
      private String cookieIdleTimeout;
      @SuppressFBWarnings(justification = "generated code")
      private CredentialPersister credentialPersister;
      @SuppressFBWarnings(justification = "generated code")
      private String cookieName;
      @SuppressFBWarnings(justification = "generated code")
      private String cookieDomain;
      @SuppressFBWarnings(justification = "generated code")
      private String cookiePath;

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

      @SuppressFBWarnings(justification = "generated code")
      public JspRememberMeConfig.JspRememberMeConfigBuilder cookieLifetime(String cookieLifetime) {
         this.cookieLifetime = cookieLifetime;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JspRememberMeConfig.JspRememberMeConfigBuilder cookieIdleTimeout(String cookieIdleTimeout) {
         this.cookieIdleTimeout = cookieIdleTimeout;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JspRememberMeConfig.JspRememberMeConfigBuilder credentialPersister(CredentialPersister credentialPersister) {
         this.credentialPersister = credentialPersister;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JspRememberMeConfig.JspRememberMeConfigBuilder cookieName(String cookieName) {
         this.cookieName = cookieName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JspRememberMeConfig.JspRememberMeConfigBuilder cookieDomain(String cookieDomain) {
         this.cookieDomain = cookieDomain;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JspRememberMeConfig.JspRememberMeConfigBuilder cookiePath(String cookiePath) {
         this.cookiePath = cookiePath;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JspRememberMeConfig build() {
         return new JspRememberMeConfig(
            this.cookieLifetime, this.cookieIdleTimeout, this.credentialPersister, this.cookieName, this.cookieDomain, this.cookiePath
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "JspRememberMeConfig.JspRememberMeConfigBuilder(cookieLifetime="
            + this.cookieLifetime
            + ", cookieIdleTimeout="
            + this.cookieIdleTimeout
            + ", credentialPersister="
            + this.credentialPersister
            + ", cookieName="
            + this.cookieName
            + ", cookieDomain="
            + this.cookieDomain
            + ", cookiePath="
            + this.cookiePath
            + ")";
      }
   }
}
