package com.airlock.iam.oauth2.application.configuration.accountregistration;

import com.airlock.iam.common.api.domain.model.store.user.UserStore;
import com.airlock.iam.login.api.application.configuration.oauth2.accountregistration.AccountRegistrationUsernameProviderConfig;
import com.airlock.iam.oauth2.domain.model.accountregistration.AccountRegistrationContextDataExtractor;
import com.airlock.iam.oauth2.domain.model.accountregistration.AccountRegistrationUserFactory;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.license.PluginLicenseRestriction;
import com.airlock.iam.plugin.api.annotation.property.EnumProperty;
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.StringListProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Plugin(
   description = "Configuration for the registration of IAM accounts with data from the provider. The created account will be persisted in the user persister of the Loginapp and linked with the provider.",
   displayName = "Automated Account Registration"
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthSocialRegistration")
public final class AccountRegistrationConfig {
   @PluginProperty(description = "Determines the username of the created IAM account.", displayName = "Determine Username", optional = false)
   private AccountRegistrationUsernameProviderConfig usernameProvider;
   @PluginListProperty(
      description = "Context Data items from the provider that will be included in the created IAM account. There must exist a corresponding context data column entry in the user persister to successfully persist the item.",
      optional = true
   )
   private List<ContextDataItemConfig> userContextDataItems;
   @StringListProperty(
      description = "The set of roles to add to the created IAM account.",
      optional = true,
      minElements = 1,
      exampleElements = {"role1", "auto-registered"}
   )
   private List<String> staticRoles;
   @EnumProperty(
      description = "Defines the status of the IAM user after creation:<ul>  <li><b>logged-in</b>: the new user will be automatically logged-in.</li>  <li><b>locked</b>: the new user will be locked, allowing an administrator to review the registration before unlocking the account. The user will be locked with reason <code>AwaitingAdminApproval</code>. The string resource key \"<code>account-registration-user-locked-message</code>\" is used for the corresponding feedback message.</li></ul>",
      defaultValue = "LOGGED_IN",
      optional = true
   )
   private StatusUponCreation statusUponCreation;

   public AccountRegistrationUserFactory logic(UserStore userStore) {
      List<AccountRegistrationContextDataExtractor> contextDataExtractors = this.userContextDataItems
         .stream()
         .map(ContextDataItemConfig::logic)
         .collect(Collectors.toList());
      boolean lockUsers = StatusUponCreation.LOCKED.equals(this.statusUponCreation);
      return AccountRegistrationUserFactory.builder()
         .userStore(userStore)
         .usernameProvider(this.usernameProvider.logic())
         .contextDataExtractors(contextDataExtractors)
         .staticRoles(this.staticRoles)
         .lockUsers(lockUsers)
         .build();
   }

   public AccountRegistrationUsernameProviderConfig getUsernameProvider() {
      return this.usernameProvider;
   }

   public List<ContextDataItemConfig> getUserContextDataItems() {
      return this.userContextDataItems;
   }

   public List<String> getStaticRoles() {
      return this.staticRoles;
   }

   public StatusUponCreation getStatusUponCreation() {
      return this.statusUponCreation;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public AccountRegistrationConfig(
      AccountRegistrationUsernameProviderConfig usernameProvider,
      List<ContextDataItemConfig> userContextDataItems,
      List<String> staticRoles,
      StatusUponCreation statusUponCreation
   ) {
      this.usernameProvider = usernameProvider;
      this.userContextDataItems = userContextDataItems;
      this.staticRoles = staticRoles;
      this.statusUponCreation = statusUponCreation;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class AccountRegistrationConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private AccountRegistrationUsernameProviderConfig usernameProvider;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<ContextDataItemConfig> userContextDataItems;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<String> staticRoles;
      @SuppressFBWarnings(justification = "generated code")
      private StatusUponCreation statusUponCreation;

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

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig.AccountRegistrationConfigBuilder usernameProvider(AccountRegistrationUsernameProviderConfig usernameProvider) {
         this.usernameProvider = usernameProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig.AccountRegistrationConfigBuilder userContextDataItem(ContextDataItemConfig userContextDataItem) {
         if (this.userContextDataItems == null) {
            this.userContextDataItems = new ArrayList<>();
         }

         this.userContextDataItems.add(userContextDataItem);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig.AccountRegistrationConfigBuilder userContextDataItems(Collection<? extends ContextDataItemConfig> userContextDataItems) {
         if (userContextDataItems == null) {
            throw new NullPointerException("userContextDataItems cannot be null");
         }

         if (this.userContextDataItems == null) {
            this.userContextDataItems = new ArrayList<>();
         }

         this.userContextDataItems.addAll(userContextDataItems);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig.AccountRegistrationConfigBuilder clearUserContextDataItems() {
         if (this.userContextDataItems != null) {
            this.userContextDataItems.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig.AccountRegistrationConfigBuilder staticRole(String staticRole) {
         if (this.staticRoles == null) {
            this.staticRoles = new ArrayList<>();
         }

         this.staticRoles.add(staticRole);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig.AccountRegistrationConfigBuilder staticRoles(Collection<? extends String> staticRoles) {
         if (staticRoles == null) {
            throw new NullPointerException("staticRoles cannot be null");
         }

         if (this.staticRoles == null) {
            this.staticRoles = new ArrayList<>();
         }

         this.staticRoles.addAll(staticRoles);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig.AccountRegistrationConfigBuilder clearStaticRoles() {
         if (this.staticRoles != null) {
            this.staticRoles.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig.AccountRegistrationConfigBuilder statusUponCreation(StatusUponCreation statusUponCreation) {
         this.statusUponCreation = statusUponCreation;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AccountRegistrationConfig build() {
         List userContextDataItems = switch (this.userContextDataItems == null ? 0 : this.userContextDataItems.size()) {
            case 0 -> Collections.emptyList();
            case 1 -> Collections.singletonList(this.userContextDataItems.get(0));
            default -> Collections.unmodifiableList(new ArrayList<>(this.userContextDataItems));
         };

         return new AccountRegistrationConfig(this.usernameProvider, userContextDataItems, switch (this.staticRoles == null ? 0 : this.staticRoles.size()) {
            case 0 -> Collections.emptyList();
            case 1 -> Collections.singletonList(this.staticRoles.get(0));
            default -> Collections.unmodifiableList(new ArrayList<>(this.staticRoles));
         }, this.statusUponCreation);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "AccountRegistrationConfig.AccountRegistrationConfigBuilder(usernameProvider="
            + this.usernameProvider
            + ", userContextDataItems="
            + this.userContextDataItems
            + ", staticRoles="
            + this.staticRoles
            + ", statusUponCreation="
            + this.statusUponCreation
            + ")";
      }
   }
}
