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

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.flow.api.domain.model.flow.FlowId;
import com.airlock.iam.flow.application.service.flow.GenericFlowConfigRepository;
import com.airlock.iam.flow.ui.infrastructure.service.FlowRedirectTargetFactory;
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.StepUiSettings;
import com.airlock.iam.publicselfservice.application.configuration.flow.PublicSelfServiceFlowConfig;
import com.airlock.iam.publicselfservice.application.configuration.ui.PublicSelfServiceUiConfig;
import com.airlock.iam.publicselfservice.application.configuration.ui.PublicSelfServiceUiConfigs;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Optional;

public final class PublicSelfServiceUiService {
   private final Optional<PublicSelfServiceUiConfigs> uiConfigs;
   private final Provider<CommonUiService> commonUiService;
   private final Provider<GenericFlowConfigRepository> flowConfigRepository;
   private final Provider<FlowRedirectTargetFactory> flowRedirectTargetFactory;
   private final Provider<GlobalUiAttributes> globalUiAttributes;

   @Inject
   public PublicSelfServiceUiService(
      Optional<PublicSelfServiceUiConfigs> uiConfigs,
      Provider<CommonUiService> commonUiService,
      Provider<GenericFlowConfigRepository> flowConfigRepository,
      Provider<FlowRedirectTargetFactory> flowRedirectTargetFactory,
      Provider<GlobalUiAttributes> globalUiAttributes
   ) {
      this.uiConfigs = uiConfigs;
      this.commonUiService = commonUiService;
      this.flowConfigRepository = flowConfigRepository;
      this.flowRedirectTargetFactory = flowRedirectTargetFactory;
      this.globalUiAttributes = globalUiAttributes;
   }

   public boolean hasUiConfig() {
      return this.getCurrentFlowId().flatMap(this::findFlowUiConfig).isPresent();
   }

   public StepUiSettings getCurrentStepUiSettings() {
      return ((CommonUiService)this.commonUiService.get()).getCurrentStepUiSettings();
   }

   public OnCompletedPublicSelfServiceSettings getOnCompletedSettings(FlowId flowId) {
      PublicSelfServiceUiConfig flowUiConfig = this.getFlowUiConfig(flowId);
      return OnCompletedPublicSelfServiceSettings.builder()
         .showConfirmationPage(flowUiConfig.isShowConfirmationPage())
         .uiTenantId(((GlobalUiAttributes)this.globalUiAttributes.get()).uiTenantId())
         .targetUri(
            ((FlowRedirectTargetFactory)this.flowRedirectTargetFactory.get())
               .getFlowRedirectTargetForUiConfig(flowUiConfig.getCompletionTarget())
               .map(target -> target.getRedirectTargetUrl(flowId))
         )
         .build();
   }

   private PublicSelfServiceUiConfig getFlowUiConfig(FlowId flowId) {
      return ViolationException.checkPresent(this.findFlowUiConfig(flowId), String.format("No UI config found for flow '%s'", flowId.getFlowId()));
   }

   public Optional<FlowId> getCurrentFlowId() {
      return this.getCurrentFlow().map(PublicSelfServiceFlowConfig::getFlowId);
   }

   private Optional<PublicSelfServiceFlowConfig> getCurrentFlow() {
      return ((GenericFlowConfigRepository)this.flowConfigRepository.get()).getConfigForCurrentFlow().map(PublicSelfServiceFlowConfig.class::cast);
   }

   private Optional<PublicSelfServiceUiConfig> findFlowUiConfig(FlowId flowId) {
      return this.uiConfigs.flatMap(c -> c.byFlowId(flowId));
   }

   public FlowFailureRedirectSettings getOnFailureSettings(FlowId flowId) {
      PublicSelfServiceUiConfig flowUiConfig = this.getFlowUiConfig(flowId);
      return ((FlowRedirectTargetFactory)this.flowRedirectTargetFactory.get())
         .getFlowFailureRedirectSettings(flowId, flowUiConfig.getFlowFailureRedirectTarget());
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class PublicSelfServiceUiServiceBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Optional<PublicSelfServiceUiConfigs> uiConfigs;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<CommonUiService> commonUiService;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<GenericFlowConfigRepository> flowConfigRepository;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<FlowRedirectTargetFactory> flowRedirectTargetFactory;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<GlobalUiAttributes> globalUiAttributes;

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

      @SuppressFBWarnings(justification = "generated code")
      public PublicSelfServiceUiService.PublicSelfServiceUiServiceBuilder uiConfigs(Optional<PublicSelfServiceUiConfigs> uiConfigs) {
         this.uiConfigs = uiConfigs;
         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      public PublicSelfServiceUiService.PublicSelfServiceUiServiceBuilder flowConfigRepository(Provider<GenericFlowConfigRepository> flowConfigRepository) {
         this.flowConfigRepository = flowConfigRepository;
         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      public PublicSelfServiceUiService.PublicSelfServiceUiServiceBuilder globalUiAttributes(Provider<GlobalUiAttributes> globalUiAttributes) {
         this.globalUiAttributes = globalUiAttributes;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public PublicSelfServiceUiService build() {
         return new PublicSelfServiceUiService(
            this.uiConfigs, this.commonUiService, this.flowConfigRepository, this.flowRedirectTargetFactory, this.globalUiAttributes
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "PublicSelfServiceUiService.PublicSelfServiceUiServiceBuilder(uiConfigs="
            + this.uiConfigs
            + ", commonUiService="
            + this.commonUiService
            + ", flowConfigRepository="
            + this.flowConfigRepository
            + ", flowRedirectTargetFactory="
            + this.flowRedirectTargetFactory
            + ", globalUiAttributes="
            + this.globalUiAttributes
            + ")";
      }
   }
}
