package com.airlock.iam.admin.infrastructure.factory.prot;

import com.airlock.iam.admin.application.configuration.users.UsersConfiguration;
import com.airlock.iam.admin.application.configuration.usersearch.filter.LatestLoginAttemptDateRangeFilter;
import com.airlock.iam.admin.application.configuration.usersearch.filter.LatestSuccessfulLoginDateRangeFilter;
import com.airlock.iam.admin.application.configuration.usersearch.filter.LockedUserFilter;
import com.airlock.iam.admin.application.configuration.usersearch.filter.SimpleLatestLoginAttemptFilter;
import com.airlock.iam.admin.application.configuration.usersearch.filter.SimpleLatestSuccessfulLoginFilter;
import com.airlock.iam.admin.application.configuration.usersearch.filter.UserSearchFilter;
import com.airlock.iam.admin.domain.model.user.Restrictions;
import com.airlock.iam.common.api.domain.model.store.user.UserStore;
import com.airlock.iam.common.api.domain.model.store.user.schema.UserSchema;
import com.airlock.iam.common.application.query.QuerySettings;
import com.airlock.iam.common.application.query.restriction.DateRestrictions;
import com.airlock.iam.common.application.query.restriction.LockRestrictionProvider;
import com.airlock.iam.common.application.query.restriction.QueryFilterRestrictionProvider;
import com.airlock.iam.common.application.query.restriction.RestrictionProviders;
import com.airlock.iam.common.application.query.restriction.RestrictionProviders.RestrictionProvidersBuilder;
import com.airlock.iam.core.domain.model.store.user.capability.UserStoreCapability;
import com.airlock.iam.core.domain.model.store.user.capability.UserStoreCapabilityFactory;
import com.google.common.collect.Lists;
import com.google.inject.Exposed;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import com.google.inject.servlet.RequestScoped;
import jakarta.inject.Named;
import jakarta.inject.Provider;
import java.text.DateFormat;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public class QuerySettingsModule extends PrivateModule {
   @Provides
   @RequestScoped
   @Exposed
   QuerySettings provideQuerySettings(
      Optional<UsersConfiguration> usersConfiguration,
      @Named("MANAGED_USERS_STORE") Provider<UserStore> userStore,
      Restrictions restrictions,
      DateFormat dateFormat
   ) {
      UserStoreCapability capability = UserStoreCapabilityFactory.of((UserStore)userStore.get());
      return QuerySettings.builder()
         .restrictions(restrictions.getRestrictions())
         .restrictionProviders(this.restrictions(usersConfiguration, userStore, dateFormat))
         .caseSensitivityDefault(usersConfiguration.map(UsersConfiguration::isCaseSensitiveSearchAsDefault).orElse(false))
         .allowsCaseInsensitiveContextDataSearch(capability.caseInsensitiveContextDataSearch())
         .build();
   }

   private RestrictionProviders restrictions(Optional<UsersConfiguration> config, Provider<UserStore> userStore, DateFormat dateFormat) {
      RestrictionProvidersBuilder builder = RestrictionProviders.builder();
      if (config.isPresent()) {
         config.get()
            .getAdvancedSearchFilters()
            .stream()
            .flatMap(filter -> this.toRestrictionProvider(filter, userStore, dateFormat).stream())
            .forEach(builder::provider);
      }

      return builder.build();
   }

   private List<QueryFilterRestrictionProvider> toRestrictionProvider(UserSearchFilter filter, Provider<UserStore> userStore, DateFormat dateFormat) {
      if (!filter.isUsableWithStore((UserStore)userStore.get())) {
         return Collections.emptyList();
      } else {
         UserSchema schema = (UserSchema)((UserStore)userStore.get()).schema();
         if (filter instanceof LockedUserFilter) {
            return Lists.newArrayList(new QueryFilterRestrictionProvider[]{new LockRestrictionProvider()});
         } else if (filter instanceof SimpleLatestSuccessfulLoginFilter) {
            return DateRestrictions.latestSuccessfulLoginPeriod(schema);
         } else if (filter instanceof SimpleLatestLoginAttemptFilter) {
            return DateRestrictions.latestLoginAttemptPeriod(schema);
         } else if (filter instanceof LatestSuccessfulLoginDateRangeFilter) {
            return DateRestrictions.latestSuccessfulLoginRange(schema, dateFormat);
         } else if (filter instanceof LatestLoginAttemptDateRangeFilter) {
            return DateRestrictions.latestLoginAttemptRange(schema, dateFormat);
         } else {
            throw new IllegalStateException("Unknown custom filter: " + filter.getClass().getName());
         }
      }
   }

   protected void configure() {
   }
}
