package com.airlock.iam.flow.shared.domain.model.termsofservice;

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.common.api.domain.model.user.CurrentLocale;
import com.airlock.iam.common.application.configuration.termsofservice.TermsOfServiceConfig;
import com.airlock.iam.common.domain.model.termsofservice.TermsOfServiceTag;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.flow.api.domain.model.step.GenericStepError;
import com.airlock.iam.flow.api.domain.model.step.StepResult;
import com.airlock.iam.flow.api.domain.model.step.StepSession;
import com.airlock.iam.flow.shared.application.configuration.termsofservice.TermsOfServiceStepConfig;
import com.airlock.iam.flow.shared.domain.service.termsofservice.TermsOfServiceService;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@LogicForConfig(TermsOfServiceStepConfig.class)
public final class TermsOfServiceStepImpl implements TermsOfServiceStep {
   private static final ELogger LOG = ELoggerFactory.getLogger(TermsOfServiceStepImpl.class);
   private final Provider<TermsOfServiceService> termsOfServiceService;
   private final Provider<CurrentLocale> currentLocale;
   private final Provider<TermsOfServiceStepSession> stepSession;

   @Inject
   public TermsOfServiceStepImpl(
      Provider<TermsOfServiceService> termsOfServiceService, Provider<CurrentLocale> currentLocale, Provider<TermsOfServiceStepSession> stepSession
   ) {
      this.termsOfServiceService = termsOfServiceService;
      this.currentLocale = currentLocale;
      this.stepSession = stepSession;
   }

   @Override
   public Optional<StepSession> createSession() {
      return Optional.of(new TermsOfServiceStepSession());
   }

   @Override
   public StepResult initialize() {
      return ((TermsOfServiceService)this.termsOfServiceService.get()).hasOpen()
         ? this.stepResultFactory().stay(TermsOfServiceStep.TermsOfServiceAction.TERMS_OF_SERVICES_RETRIEVAL_REQUIRED).build()
         : this.stepResultFactory().success().build();
   }

   @Override
   public String getDescription() {
      return "Terms of Services Flow Step";
   }

   @Override
   public StepResult retrieve() {
      if (!((TermsOfServiceService)this.termsOfServiceService.get()).hasOpen()) {
         return this.stepResultFactory().fail(GenericStepError.UNEXPECTED_CALL).build();
      }

      ((TermsOfServiceStepSession)this.stepSession.get()).setRetrieveCalled(true);
      List<TermsOfServiceConfig> allOpen = ((TermsOfServiceService)this.termsOfServiceService.get()).getAllOpen();
      this.addTagsToSession(allOpen);
      return this.stepResultFactory()
         .stay(TermsOfServiceStep.TermsOfServiceAction.TERMS_OF_SERVICES_ACCEPT_REQUIRED)
         .resultData(new TermsOfServiceEntries(this.toEntries(allOpen)))
         .build();
   }

   @Override
   public StepResult deny() {
      return this.stepResultFactory().fail(TermsOfServiceStep.TermsOfServiceError.TERMS_OF_SERVICES_DENIED).build();
   }

   @Override
   public StepResult acceptRetrieved() {
      if (!((TermsOfServiceStepSession)this.stepSession.get()).isRetrieveCalled()) {
         return this.stepResultFactory().fail(GenericStepError.UNEXPECTED_CALL).build();
      }

      ((TermsOfServiceService)this.termsOfServiceService.get()).accept(((TermsOfServiceStepSession)this.stepSession.get()).getRetrievedTags());
      return this.stepResultFactory().success().build();
   }

   private void addTagsToSession(List<TermsOfServiceConfig> allOpen) {
      allOpen.stream()
         .map(TermsOfServiceConfig::getTag)
         .map(TermsOfServiceTag::new)
         .forEach(tag -> ((TermsOfServiceStepSession)this.stepSession.get()).getRetrievedTags().add(tag));
   }

   private List<TermsOfServiceEntry> toEntries(List<TermsOfServiceConfig> termsOfServices) {
      return termsOfServices.stream().map(this::toEntry).collect(Collectors.toList());
   }

   private TermsOfServiceEntry toEntry(TermsOfServiceConfig termsOfServices) {
      return new TermsOfServiceEntry(
         new TermsOfServiceTag(termsOfServices.getTag()), termsOfServices.getLogic().getDisclaimerText(((CurrentLocale)this.currentLocale.get()).getLanguage())
      );
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class TermsOfServiceStepImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Provider<TermsOfServiceService> termsOfServiceService;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<CurrentLocale> currentLocale;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<TermsOfServiceStepSession> stepSession;

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

      @SuppressFBWarnings(justification = "generated code")
      public TermsOfServiceStepImpl.TermsOfServiceStepImplBuilder termsOfServiceService(Provider<TermsOfServiceService> termsOfServiceService) {
         this.termsOfServiceService = termsOfServiceService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TermsOfServiceStepImpl.TermsOfServiceStepImplBuilder currentLocale(Provider<CurrentLocale> currentLocale) {
         this.currentLocale = currentLocale;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TermsOfServiceStepImpl.TermsOfServiceStepImplBuilder stepSession(Provider<TermsOfServiceStepSession> stepSession) {
         this.stepSession = stepSession;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TermsOfServiceStepImpl build() {
         return new TermsOfServiceStepImpl(this.termsOfServiceService, this.currentLocale, this.stepSession);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "TermsOfServiceStepImpl.TermsOfServiceStepImplBuilder(termsOfServiceService="
            + this.termsOfServiceService
            + ", currentLocale="
            + this.currentLocale
            + ", stepSession="
            + this.stepSession
            + ")";
      }
   }
}
