package com.airlock.iam.authentication.infrastructure.service.ui;

import com.airlock.iam.authentication.application.configuration.ui.AuthenticationUiConfig;
import com.airlock.iam.authentication.application.configuration.ui.AuthenticationUiConfigs;
import com.airlock.iam.authentication.application.settings.AccessSettings;
import com.airlock.iam.authentication.domain.model.session.CurrentApplicationId;
import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.base.api.infrastructure.plugin.PluginConfigToLogic;
import com.airlock.iam.flow.api.application.configuration.step.FlowStepConfig;
import com.airlock.iam.flow.api.domain.model.flow.ApplicationId;
import com.airlock.iam.flow.api.domain.model.flow.FlowId;
import com.airlock.iam.flow.ui.application.configuration.StepUiConfig;
import com.airlock.iam.flow.ui.infrastructure.service.FlowRedirectTargetFactory;
import com.airlock.iam.flow.ui.infrastructure.service.OnLogout;
import com.airlock.iam.flow.ui.infrastructure.service.ui.CommonUiService;
import com.airlock.iam.flow.ui.infrastructure.service.ui.GlobalUiAttributes;
import com.airlock.iam.flow.ui.infrastructure.settings.FlowFailureRedirectSettings;
import com.airlock.iam.flow.ui.infrastructure.settings.NonFlowUiSettings;
import com.airlock.iam.flow.ui.infrastructure.settings.StepUiSettings;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public class AuthenticationUiService {
   private final Optional<AuthenticationUiConfigs> uiConfigs;
   private final Provider<CommonUiService> commonUiService;
   private final Provider<Optional<CurrentApplicationId>> applicationId;
   private final PluginConfigToLogic pluginConfigToLogic;
   private final GlobalUiAttributes globalUiAttributes;
   private final List<AuthenticationPageSettingsAttributesProvider> authPageSettingsAttributesProviders;
   private final Provider<FlowRedirectTargetFactory> flowRedirectTargetFactory;

   @Inject
   public AuthenticationUiService(
      Optional<AuthenticationUiConfigs> uiConfigs,
      Provider<CommonUiService> commonUiService,
      Provider<Optional<CurrentApplicationId>> applicationId,
      PluginConfigToLogic pluginConfigToLogic,
      GlobalUiAttributes globalUiAttributes,
      List<AuthenticationPageSettingsAttributesProvider> authPageSettingsAttributesProviders,
      Provider<FlowRedirectTargetFactory> flowRedirectTargetFactory
   ) {
      this.uiConfigs = uiConfigs;
      this.commonUiService = commonUiService;
      this.applicationId = applicationId;
      this.pluginConfigToLogic = pluginConfigToLogic;
      this.globalUiAttributes = globalUiAttributes;
      this.authPageSettingsAttributesProviders = authPageSettingsAttributesProviders;
      this.flowRedirectTargetFactory = flowRedirectTargetFactory;
   }

   public boolean hasUiConfig() {
      return this.getCurrentApplicationId().flatMap(this::findApplicationUiConfig).isPresent();
   }

   public OnLogout getOnLogout() {
      return this.uiConfigs
         .flatMap(AuthenticationUiConfigs::getOnLogout)
         .map(this.pluginConfigToLogic::getLogic)
         .orElseGet(
            () -> this.getUiTenantId()
               .map(DefaultShowLogoutDisclaimerPage::defaultShowLogoutDisclaimerPage)
               .orElse(DefaultShowLogoutDisclaimerPage.defaultShowLogoutDisclaimerPage())
         );
   }

   public Optional<AccessSettings> getAccessSettings() {
      return this.uiConfigs.map(c -> new AccessSettings(c.getSsoParameterNames()));
   }

   public NonFlowUiSettings getNonFlowAuthenticationUiSettings() {
      return this.uiConfigs
         .map(AuthenticationUiConfigs::getNonFlowUiSettings)
         .map(this.pluginConfigToLogic::getLogic)
         .map(NonFlowUiSettingsService::toSettings)
         .orElse(this.getDefaultNonFlowAuthenticationUiSettings());
   }

   private NonFlowUiSettings getDefaultNonFlowAuthenticationUiSettings() {
      return NonFlowUiSettings.builder().pageSettings(Collections.emptyMap()).uiTenantId(this.getUiTenantId()).build();
   }

   private Optional<String> getUiTenantId() {
      return this.globalUiAttributes.uiTenantId();
   }

   public StepUiSettings getCurrentStepUiSettings() {
      StepUiSettings stepUiSettings = this.commonUiService().getCurrentStepUiSettings();
      FlowStepConfig stepConfig = this.commonUiService().getCurrentFlowStepConfig();
      Optional<StepUiConfig> stepUiConfig = this.commonUiService().getCurrentFlowStepUiConfig();
      this.authPageSettingsAttributesProviders
         .forEach(provider -> stepUiSettings.getPageSettings().putAll(provider.getPageSettingsAttributes(stepConfig, stepUiConfig)));
      return stepUiSettings;
   }

   public Optional<ApplicationId> getCurrentApplicationId() {
      return ((Optional)this.applicationId.get()).map(CurrentApplicationId::applicationId);
   }

   public Optional<AuthenticationUiConfig> getCurrentApplicationUiConfig() {
      return this.getCurrentApplicationId().flatMap(this::findApplicationUiConfig);
   }

   private Optional<AuthenticationUiConfig> findApplicationUiConfig(ApplicationId applicationId) {
      return this.uiConfigs.flatMap(c -> c.byApplicationId(applicationId));
   }

   private AuthenticationUiConfig getFlowUiConfig(ApplicationId applicationId) {
      return ViolationException.checkPresent(
         this.findApplicationUiConfig(applicationId), String.format("No UI config found for flow '%s'", applicationId.getApplicationId())
      );
   }

   private CommonUiService commonUiService() {
      return (CommonUiService)this.commonUiService.get();
   }

   public FlowFailureRedirectSettings getOnFailureSettings(ApplicationId applicationId) {
      AuthenticationUiConfig flowUiConfig = this.getFlowUiConfig(applicationId);
      return ((FlowRedirectTargetFactory)this.flowRedirectTargetFactory.get())
         .getFlowFailureRedirectSettings(new FlowId(applicationId.getApplicationId()), flowUiConfig.getFlowFailureRedirectTarget());
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class AuthenticationUiServiceBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Optional<AuthenticationUiConfigs> uiConfigs;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<CommonUiService> commonUiService;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<Optional<CurrentApplicationId>> applicationId;
      @SuppressFBWarnings(justification = "generated code")
      private PluginConfigToLogic pluginConfigToLogic;
      @SuppressFBWarnings(justification = "generated code")
      private GlobalUiAttributes globalUiAttributes;
      @SuppressFBWarnings(justification = "generated code")
      private List<AuthenticationPageSettingsAttributesProvider> authPageSettingsAttributesProviders;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<FlowRedirectTargetFactory> flowRedirectTargetFactory;

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

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationUiService.AuthenticationUiServiceBuilder uiConfigs(Optional<AuthenticationUiConfigs> uiConfigs) {
         this.uiConfigs = uiConfigs;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationUiService.AuthenticationUiServiceBuilder commonUiService(Provider<CommonUiService> commonUiService) {
         this.commonUiService = commonUiService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationUiService.AuthenticationUiServiceBuilder applicationId(Provider<Optional<CurrentApplicationId>> applicationId) {
         this.applicationId = applicationId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationUiService.AuthenticationUiServiceBuilder pluginConfigToLogic(PluginConfigToLogic pluginConfigToLogic) {
         this.pluginConfigToLogic = pluginConfigToLogic;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationUiService.AuthenticationUiServiceBuilder globalUiAttributes(GlobalUiAttributes globalUiAttributes) {
         this.globalUiAttributes = globalUiAttributes;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationUiService.AuthenticationUiServiceBuilder authPageSettingsAttributesProviders(
         List<AuthenticationPageSettingsAttributesProvider> authPageSettingsAttributesProviders
      ) {
         this.authPageSettingsAttributesProviders = authPageSettingsAttributesProviders;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationUiService.AuthenticationUiServiceBuilder flowRedirectTargetFactory(Provider<FlowRedirectTargetFactory> flowRedirectTargetFactory) {
         this.flowRedirectTargetFactory = flowRedirectTargetFactory;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationUiService build() {
         return new AuthenticationUiService(
            this.uiConfigs,
            this.commonUiService,
            this.applicationId,
            this.pluginConfigToLogic,
            this.globalUiAttributes,
            this.authPageSettingsAttributesProviders,
            this.flowRedirectTargetFactory
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "AuthenticationUiService.AuthenticationUiServiceBuilder(uiConfigs="
            + this.uiConfigs
            + ", commonUiService="
            + this.commonUiService
            + ", applicationId="
            + this.applicationId
            + ", pluginConfigToLogic="
            + this.pluginConfigToLogic
            + ", globalUiAttributes="
            + this.globalUiAttributes
            + ", authPageSettingsAttributesProviders="
            + this.authPageSettingsAttributesProviders
            + ", flowRedirectTargetFactory="
            + this.flowRedirectTargetFactory
            + ")";
      }
   }
}
