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

import com.airlock.iam.common.application.configuration.sso.SsoTicketContextDataExtractorConfig;
import com.airlock.iam.core.application.configuration.AcceptedSsoTicketRepositoryConfig;
import com.airlock.iam.core.application.configuration.store.user.UserStoreProvider;
import com.airlock.iam.core.misc.authen.UsernameTransformer;
import com.airlock.iam.core.misc.util.ticket.TicketDecoder;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
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.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.api.exception.PropertyConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.PluginListPropertyValueReader;
import com.airlock.iam.plugin.api.valuereader.PluginPropertyValueReader;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import com.airlock.iam.plugin.impl.PropertyNotFoundException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.List;
import java.util.Optional;

public abstract class BaseSsoTicketRequestAuthenticationConfig extends BaseRequestAuthenticationConfig {
   @PluginProperty(description = "Determines where the SSO ticket is to be extracted from.", displayName = "SSO Ticket Extractor", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private SsoTicketExtractorConfig ssoTicketExtractor;
   private static final String SSO_TICKET_EXTRACTOR = "ssoTicketExtractor";
   @PluginProperty(
      description = "<p>The ticket decoder plugin used to decode the SSO ticket.</p><p><b>Security note:</b> If tickets are transported via the web browser (in the URL), they need to be protected. Make sure to use an appropriate ticket decoder securing the ticket (e.g. digitally signed and/or encrypted)! </p>",
      optional = false
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private TicketDecoder ticketDecoder;
   @PluginProperty(
      description = "<p>Configures the repository used to store accepted SSO tickets and reject previously accepted ones.</p>\n<p>The in-memory repository cannot be used if multiple instances of IAM are deployed in parallel (failover, horizontal scaling).\nFurthermore, the in-memory repository does not preserve previously accepted SSO tickets across IAM restarts.</p>",
      displayName = "Accepted SSO Tickets Repository",
      optional = false,
      globalPluginReference = "globalAcceptedSsoTicketSettings"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private AcceptedSsoTicketRepositoryConfig acceptedSsoTicketRepository;
   @PluginListProperty(description = "List of ticket context data extractors that extract custom data from the ticket.", optional = true)
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private List<SsoTicketContextDataExtractorConfig> contextDataExtractors;
   @StringProperty(description = "The ticket key containing the username.", optional = true, defaultValue = "username")
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String usernameKey;
   @StringProperty(
      description = "<p>The ticket key containing the provided username, which is used for logging and possibly displayed.</p>\n<p>This is not combinable with Username Transformation. If the ticket does not contain a provided username,\nthe value from \"Username Key\" is used.</p>",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String providedUsernameKey;
   static final String PROVIDED_USERNAME_KEY_FIELD = "providedUsernameKey";
   @StringProperty(
      description = "The ticket key containing the user's roles. If not configured, no roles are extracted from the ticket.",
      optional = true,
      exampleValues = "roles"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String rolesKey;

   protected BaseSsoTicketRequestAuthenticationConfig(
      UserStoreProvider userStore,
      List<UsernameTransformer> usernameTransformers,
      List<String> staticRoles,
      List<String> rolesBlocklist,
      SsoTicketExtractorConfig ssoTicketExtractor,
      TicketDecoder ticketDecoder,
      @Nullable AcceptedSsoTicketRepositoryConfig acceptedSsoTicketRepository,
      List<SsoTicketContextDataExtractorConfig> contextDataExtractors,
      String usernameKey,
      String providedUsernameKey,
      String rolesKey
   ) {
      super(userStore, usernameTransformers, staticRoles, rolesBlocklist);
      this.acceptedSsoTicketRepository = acceptedSsoTicketRepository;
      this.ssoTicketExtractor = ssoTicketExtractor;
      this.ticketDecoder = ticketDecoder;
      this.contextDataExtractors = contextDataExtractors;
      this.usernameKey = usernameKey;
      this.providedUsernameKey = providedUsernameKey;
      this.rolesKey = rolesKey;
   }

   public Optional<String> getRolesKey() {
      return Optional.ofNullable(this.rolesKey);
   }

   public Optional<String> getProvidedUsernameKey() {
      return Optional.ofNullable(this.providedUsernameKey);
   }

   public SsoTicketExtractorConfig getSsoTicketExtractor() {
      return this.ssoTicketExtractor;
   }

   public TicketDecoder getTicketDecoder() {
      return this.ticketDecoder;
   }

   public AcceptedSsoTicketRepositoryConfig getAcceptedSsoTicketRepository() {
      return this.acceptedSsoTicketRepository;
   }

   public List<SsoTicketContextDataExtractorConfig> getContextDataExtractors() {
      return this.contextDataExtractors;
   }

   public String getUsernameKey() {
      return this.usernameKey;
   }

   @ConfigurationValidator
   static void validateTicketExtractors(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment valEnv) throws ConfigurationException {
      try {
         PluginConfiguration ssoTicketExtractor = PluginPropertyValueReader.effectivePluginPropertyValue(config, "ssoTicketExtractor", env, context);
         if (ssoTicketExtractor.getPluginClassName().equals("com.airlock.iam.authentication.application.configuration.sso.LoginappUiSsoTicketExtractorConfig")
            || ssoTicketExtractor.getPluginClassName()
               .equals("com.airlock.iam.authentication.application.configuration.sso.OpenIdConnectSsoTicketLoginHintExtractorConfig")) {
            throw new PropertyConstraintViolationException(
               "ssoTicketExtractor", config, env, context, "This SSO Ticket Extractor implementation cannot be used here."
            );
         }
      } catch (PropertyNotFoundException var5) {
      }
   }

   @ConfigurationValidator
   static void validateProvidedUsernameKey(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment valEnv) throws ConfigurationException {
      List<PluginConfiguration> usernameTransformers = PluginListPropertyValueReader.effectivePluginListPropertyValue(
         config, "usernameTransformers", env, context
      );
      String providedUsernameKey = StringPropertyValueReader.effectiveStringConfigValue(config, "providedUsernameKey", env, context);
      if (!usernameTransformers.isEmpty() && providedUsernameKey != null) {
         throw new PropertyConfigurationException(
            config,
            env,
            context,
            "\"Provided Username Key\" cannot be combined with \"Username Transformers\".",
            new String[]{"providedUsernameKey", "usernameTransformers"}
         );
      }
   }

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