package com.airlock.iam.admin.application.service.settings;

import com.airlock.iam.admin.api.domain.model.user.AuthenticationMethods;
import com.airlock.iam.admin.api.domain.model.user.ManagedUser;
import com.airlock.iam.admin.api.domain.service.user.ManagedUserRepository;
import com.airlock.iam.admin.application.configuration.users.UsersConfiguration;
import com.airlock.iam.admin.application.service.SettingsProvider;
import com.airlock.iam.admin.application.service.accountlink.AccountLinkService;
import com.airlock.iam.admin.application.service.authmethod.AuthenticationMethodService;
import com.airlock.iam.admin.application.service.permission.AdminappPermissionsService;
import com.airlock.iam.admin.domain.model.administrator.ExtendedCurrentAdministrator;
import com.airlock.iam.admin.domain.model.authmethod.AuthenticationMethod;
import com.airlock.iam.admin.domain.model.token.generic.GenericAuthenticationMethod;
import com.airlock.iam.admin.domain.model.user.UserLockedVisibility;
import com.airlock.iam.admin.domain.model.user.UserSpecificSettings;
import com.airlock.iam.admin.domain.service.access.AdminappAccessController;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.common.api.domain.model.store.user.IdentityChangingUserStore;
import com.airlock.iam.common.api.domain.model.valueprovider.ValueProvider;
import com.airlock.iam.common.application.configuration.user.UserManagementExtensionConfig;
import com.airlock.iam.common.application.configuration.usertrail.UserTrailLogRepositoryConfig;
import com.airlock.iam.common.domain.model.user.profileitems.UserProfileItems;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Provider;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.apache.commons.lang3.Strings;

public class AdminappSettingsService {
   private final AdminappPermissionsService.SystemPermissions permissions;
   private final Set<SettingsProvider> settingsProviders;
   private final Provider<UserSpecificSettings> userSpecificSettings;
   private final Optional<UsersConfiguration> usersConfiguration;
   private final Provider<ManagedUserRepository> userRepository;
   private final Provider<AuthenticationMethodService> authMethodService;
   private final Provider<TokenControllerSettingsBuilder> tokenControllerSettingsBuilder;
   private final Provider<UserProfileItems> profileItems;
   private final Provider<Optional<IdentityChangingUserStore>> identityChangingUserStore;
   private final Provider<Optional<AccountLinkService>> accountLinkService;
   private final Optional<ValueProvider<String>> usernamePrefill;
   private final Provider<AdminappAccessController> accessController;
   private final Optional<UserTrailLogRepositoryConfig> userTrailLogRepositoryConfig;
   private final ExtendedCurrentAdministrator currentAdministrator;

   public AdminappPageSettings getSettings() {
      AdminappPageSettings.AdminappPageSettingsBuilder builder = AdminappPageSettings.builder();
      this.settingsProviders
         .stream()
         .filter(provider -> this.permissions.getAdminappPermissions().isPageAccessible(provider.page()))
         .filter(provider -> provider.getSettings().isPresent())
         .forEach(provider -> builder.page(provider.page().getPageName(), provider.getSettings().get()));
      return builder.build();
   }

   public UserDetailSettings getGenericUserSettings() {
      if (this.usersConfiguration.isEmpty()) {
         return UserDetailSettings.builder().build();
      }

      List<AuthenticationMethod> possibleNextAuthMethods = ((AuthenticationMethodService)this.authMethodService.get()).getAllPossibleNextAuthMethods();
      return UserDetailSettings.builder()
         .allowsUsernameChange(((Optional)this.identityChangingUserStore.get()).isPresent())
         .authMethodNameToId(((AuthenticationMethodService)this.authMethodService.get()).authMethodIdToTokenType())
         .generateUsername(this.usersConfiguration.get().getUserIdentityGenerator().isPresent())
         .usernamePrefill(this.usernamePrefill.<String>map(ValueProvider::getValue).orElse(null))
         .userLockedVisibility(UserLockedVisibility.HIDE)
         .enableMultipleNextAuthMethods(this.usersConfiguration.get().isEnableMultipleNextAuthMethods())
         .genericAuthenticationMethodIds(this.genericAuthMethodIds())
         .userManagementExtensionIds(this.userManagementIds())
         .possibleNextAuthMethods(possibleNextAuthMethods(possibleNextAuthMethods))
         .overviewProfileItems(UserProfileItemSettings.createGeneric(((UserProfileItems)this.profileItems.get()).getListProfileItems()))
         .rowsOnUserDetailPage(UserProfileItemSettings.createGeneric(((UserProfileItems)this.profileItems.get()).getDetailProfileItems()))
         .showAuthMethodMigrationSection(this.usersConfiguration.get().isShowMigrationSection())
         .build();
   }

   public UserDetailSettings getUserDetailSettings(UserId userId) {
      ManagedUser user = ((ManagedUserRepository)this.userRepository.get()).getById(userId);
      List<AuthenticationMethod> visibleAuthenticationMethods = ((AuthenticationMethodService)this.authMethodService.get())
         .getVisibleAuthenticationMethods(userId);
      List<AuthenticationMethod> possibleNextAuthMethods = ((AuthenticationMethodService)this.authMethodService.get()).getPossibleNextAuthMethods(userId);
      UserDetailSettings.UserDetailSettingsBuilder settings = UserDetailSettings.builder()
         .allowsUsernameChange(((Optional)this.identityChangingUserStore.get()).isPresent())
         .authMethodNameToId(((AuthenticationMethodService)this.authMethodService.get()).authMethodIdToTokenType())
         .availableUserRoles(((UserSpecificSettings)this.userSpecificSettings.get()).getAvailableUserRoles())
         .editable(((UserSpecificSettings)this.userSpecificSettings.get()).isEditable())
         .generateUsername(this.usersConfiguration.flatMap(UsersConfiguration::getUserIdentityGenerator).isPresent())
         .usernamePrefill(this.usernamePrefill.<String>map(ValueProvider::getValue).orElse(null))
         .enableMultipleNextAuthMethods(this.usersConfiguration.map(UsersConfiguration::isEnableMultipleNextAuthMethods).orElse(false))
         .genericAuthenticationMethodIds(this.genericAuthMethodIds())
         .userManagementExtensionIds(this.userManagementIds())
         .lockReasons(((UserSpecificSettings)this.userSpecificSettings.get()).getLockingSettings().getLockReasons())
         .overviewProfileItems(
            UserProfileItemSettings.createWithUserData(((UserProfileItems)this.profileItems.get()).getListProfileItems(), user.getContextData().asKeyValueMap())
         )
         .possibleNextAuthMethods(possibleNextAuthMethods(possibleNextAuthMethods))
         .rowsOnUserDetailPage(
            UserProfileItemSettings.createWithUserData(
               ((UserProfileItems)this.profileItems.get()).getDetailProfileItems(), user.getContextData().asKeyValueMap()
            )
         )
         .showAuthenticationMethodManagement(
            !((AuthenticationMethodService)this.authMethodService.get()).getPossibleActiveAuthMethods(userId).isEmpty()
               || !possibleNextAuthMethods.isEmpty()
               || !((AuthenticationMethodService)this.authMethodService.get()).getPossibleNewAuthMethods(userId).isEmpty()
         )
         .showAuthMethodMigrationSection(((UserSpecificSettings)this.userSpecificSettings.get()).isShowCredentialMigrationSection())
         .showRememberMeSection(this.showRememberMeSection())
         .showTempLockingSection(this.usersConfiguration.isPresent() && this.tempLockingConfigured())
         .showUserValidSection(((UserSpecificSettings)this.userSpecificSettings.get()).isShowUserValidSection())
         .userLockedVisibility(this.usersConfiguration.isPresent() ? this.usersConfiguration.get().getUserLockedSection() : UserLockedVisibility.HIDE)
         .visibleAuthMethodIds(
            visibleAuthenticationMethods.stream().map(AuthenticationMethod::getTokenType).map(AuthenticationMethod.TokenType::getId).toList()
         )
         .showAccountLinkTab(this.isShowAccountLinkTab(userId))
         .hasUserTrailLogDatabaseConnection(this.userTrailLogRepositoryConfig.isPresent())
         .tokenSettings(((TokenControllerSettingsBuilder)this.tokenControllerSettingsBuilder.get()).build(userId))
         .deletionAllowed(this.isDeletionAllowed(userId));
      return settings.build();
   }

   private static List<String> possibleNextAuthMethods(List<AuthenticationMethod> possibleNextAuthMethods) {
      return possibleNextAuthMethods.stream().map(AuthenticationMethod::getConfiguredId).map(AuthenticationMethods.AuthenticationMethodId::getId).toList();
   }

   public boolean isDeletionAllowed(UserId userId) {
      return !((UserSpecificSettings)this.userSpecificSettings.get()).isAdminCannotDeleteSameNameUser()
         || !Strings.CI.equals(userId.getValue(), this.currentAdministrator.getName());
   }

   private boolean isShowAccountLinkTab(UserId userId) {
      return ((Optional)this.accountLinkService.get()).<Boolean>map(service -> !service.accountLinks(userId).isEmpty()).orElse(false);
   }

   private boolean tempLockingConfigured() {
      return ((UserSpecificSettings)this.userSpecificSettings.get()).getLockingSettings().getTemporaryLockingConfig().isPresent();
   }

   private boolean showRememberMeSection() {
      return this.usersConfiguration.isPresent() && this.isRememberMeConfigured(this.usersConfiguration.get());
   }

   private boolean isRememberMeConfigured(UsersConfiguration config) {
      return config.getJspLoginappRememberMeSettings().isPresent() || config.isRememberMeManagementEnabled();
   }

   private List<String> userManagementIds() {
      return this.usersConfiguration
         .stream()
         .map(UsersConfiguration::getUserManagementExtensions)
         .flatMap(Collection::stream)
         .<String>map(UserManagementExtensionConfig::getId)
         .filter(((AdminappAccessController)this.accessController.get())::isUserManagementExtensionDisplayed)
         .toList();
   }

   private List<String> genericAuthMethodIds() {
      return ((AuthenticationMethodService)this.authMethodService.get())
         .getGenericAuthenticationMethods()
         .stream()
         .filter(GenericAuthenticationMethod.class::isInstance)
         .map(GenericAuthenticationMethod.class::cast)
         .map(AuthenticationMethod::getTokenType)
         .map(AuthenticationMethod.TokenType::getId)
         .toList();
   }

   @SuppressFBWarnings(justification = "generated code")
   AdminappSettingsService(
      AdminappPermissionsService.SystemPermissions permissions,
      Set<SettingsProvider> settingsProviders,
      Provider<UserSpecificSettings> userSpecificSettings,
      Optional<UsersConfiguration> usersConfiguration,
      Provider<ManagedUserRepository> userRepository,
      Provider<AuthenticationMethodService> authMethodService,
      Provider<TokenControllerSettingsBuilder> tokenControllerSettingsBuilder,
      Provider<UserProfileItems> profileItems,
      Provider<Optional<IdentityChangingUserStore>> identityChangingUserStore,
      Provider<Optional<AccountLinkService>> accountLinkService,
      Optional<ValueProvider<String>> usernamePrefill,
      Provider<AdminappAccessController> accessController,
      Optional<UserTrailLogRepositoryConfig> userTrailLogRepositoryConfig,
      ExtendedCurrentAdministrator currentAdministrator
   ) {
      this.permissions = permissions;
      this.settingsProviders = settingsProviders;
      this.userSpecificSettings = userSpecificSettings;
      this.usersConfiguration = usersConfiguration;
      this.userRepository = userRepository;
      this.authMethodService = authMethodService;
      this.tokenControllerSettingsBuilder = tokenControllerSettingsBuilder;
      this.profileItems = profileItems;
      this.identityChangingUserStore = identityChangingUserStore;
      this.accountLinkService = accountLinkService;
      this.usernamePrefill = usernamePrefill;
      this.accessController = accessController;
      this.userTrailLogRepositoryConfig = userTrailLogRepositoryConfig;
      this.currentAdministrator = currentAdministrator;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class AdminappSettingsServiceBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private AdminappPermissionsService.SystemPermissions permissions;
      @SuppressFBWarnings(justification = "generated code")
      private Set<SettingsProvider> settingsProviders;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<UserSpecificSettings> userSpecificSettings;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<UsersConfiguration> usersConfiguration;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<ManagedUserRepository> userRepository;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<AuthenticationMethodService> authMethodService;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<TokenControllerSettingsBuilder> tokenControllerSettingsBuilder;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<UserProfileItems> profileItems;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<Optional<IdentityChangingUserStore>> identityChangingUserStore;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<Optional<AccountLinkService>> accountLinkService;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<ValueProvider<String>> usernamePrefill;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<AdminappAccessController> accessController;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<UserTrailLogRepositoryConfig> userTrailLogRepositoryConfig;
      @SuppressFBWarnings(justification = "generated code")
      private ExtendedCurrentAdministrator currentAdministrator;

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

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder permissions(AdminappPermissionsService.SystemPermissions permissions) {
         this.permissions = permissions;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder settingsProviders(Set<SettingsProvider> settingsProviders) {
         this.settingsProviders = settingsProviders;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder userSpecificSettings(Provider<UserSpecificSettings> userSpecificSettings) {
         this.userSpecificSettings = userSpecificSettings;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder usersConfiguration(Optional<UsersConfiguration> usersConfiguration) {
         this.usersConfiguration = usersConfiguration;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder userRepository(Provider<ManagedUserRepository> userRepository) {
         this.userRepository = userRepository;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder authMethodService(Provider<AuthenticationMethodService> authMethodService) {
         this.authMethodService = authMethodService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder tokenControllerSettingsBuilder(
         Provider<TokenControllerSettingsBuilder> tokenControllerSettingsBuilder
      ) {
         this.tokenControllerSettingsBuilder = tokenControllerSettingsBuilder;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder profileItems(Provider<UserProfileItems> profileItems) {
         this.profileItems = profileItems;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder identityChangingUserStore(
         Provider<Optional<IdentityChangingUserStore>> identityChangingUserStore
      ) {
         this.identityChangingUserStore = identityChangingUserStore;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder accountLinkService(Provider<Optional<AccountLinkService>> accountLinkService) {
         this.accountLinkService = accountLinkService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder usernamePrefill(Optional<ValueProvider<String>> usernamePrefill) {
         this.usernamePrefill = usernamePrefill;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder accessController(Provider<AdminappAccessController> accessController) {
         this.accessController = accessController;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder userTrailLogRepositoryConfig(
         Optional<UserTrailLogRepositoryConfig> userTrailLogRepositoryConfig
      ) {
         this.userTrailLogRepositoryConfig = userTrailLogRepositoryConfig;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService.AdminappSettingsServiceBuilder currentAdministrator(ExtendedCurrentAdministrator currentAdministrator) {
         this.currentAdministrator = currentAdministrator;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSettingsService build() {
         return new AdminappSettingsService(
            this.permissions,
            this.settingsProviders,
            this.userSpecificSettings,
            this.usersConfiguration,
            this.userRepository,
            this.authMethodService,
            this.tokenControllerSettingsBuilder,
            this.profileItems,
            this.identityChangingUserStore,
            this.accountLinkService,
            this.usernamePrefill,
            this.accessController,
            this.userTrailLogRepositoryConfig,
            this.currentAdministrator
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "AdminappSettingsService.AdminappSettingsServiceBuilder(permissions="
            + this.permissions
            + ", settingsProviders="
            + this.settingsProviders
            + ", userSpecificSettings="
            + this.userSpecificSettings
            + ", usersConfiguration="
            + this.usersConfiguration
            + ", userRepository="
            + this.userRepository
            + ", authMethodService="
            + this.authMethodService
            + ", tokenControllerSettingsBuilder="
            + this.tokenControllerSettingsBuilder
            + ", profileItems="
            + this.profileItems
            + ", identityChangingUserStore="
            + this.identityChangingUserStore
            + ", accountLinkService="
            + this.accountLinkService
            + ", usernamePrefill="
            + this.usernamePrefill
            + ", accessController="
            + this.accessController
            + ", userTrailLogRepositoryConfig="
            + this.userTrailLogRepositoryConfig
            + ", currentAdministrator="
            + this.currentAdministrator
            + ")";
      }
   }
}
