package com.airlock.iam.login.domain.service.termsofservice;

import com.airlock.iam.common.api.domain.model.contextdata.ContextData;
import com.airlock.iam.common.application.configuration.termsofservice.TermsOfServiceConfig;
import com.airlock.iam.common.domain.model.contextdata.ContextDataFactory;
import com.airlock.iam.common.domain.model.principal.UserPrincipal;
import com.airlock.iam.common.domain.model.termsofservice.TermsOfServiceTag;
import com.airlock.iam.common.domain.service.termsofservice.CommonTermsOfServiceService;
import com.airlock.iam.common.infrastructure.contextdata.ContextDataFactoryImpl;
import com.airlock.iam.flow.shared.domain.service.termsofservice.TermsOfServiceService;
import com.airlock.iam.log.api.signing.SigningLogger;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class AuthenticationTermsOfServiceServiceImpl implements TermsOfServiceService {
   private final SigningLogger signingLogger;
   private final CommonTermsOfServiceService commonService;
   private final Provider<UserPrincipal> principal;
   private final ContextDataFactory contextDataFactory;

   @Inject
   public AuthenticationTermsOfServiceServiceImpl(
      SigningLogger signingLogger, CommonTermsOfServiceService commonService, Provider<UserPrincipal> principal, ContextDataFactory contextDataFactory
   ) {
      this.signingLogger = signingLogger;
      this.commonService = commonService;
      this.principal = principal;
      this.contextDataFactory = contextDataFactory;
   }

   @Override
   public boolean hasOpen() {
      return this.commonService.hasOpen(this.getContextData());
   }

   @Override
   public List<TermsOfServiceConfig> getAllOpen() {
      return this.commonService.getAllOpen(this.getContextData());
   }

   @Override
   public void accept(Set<TermsOfServiceTag> tags) {
      List<TermsOfServiceConfig> termsOfServicesToAccept = this.commonService.collectTermsOfServicesToAccept(tags);
      termsOfServicesToAccept.forEach(this::storeAcceptedTos);
      Set<String> acceptedTags = termsOfServicesToAccept.stream().map(TermsOfServiceConfig::getTag).collect(Collectors.toSet());
      this.signingLogger
         .log("User \"%s\" accepted the following terms of services: %s", new Object[]{((UserPrincipal)this.principal.get()).getName(), acceptedTags});
   }

   private void storeAcceptedTos(TermsOfServiceConfig tos) {
      ((UserPrincipal)this.principal.get())
         .user()
         .putAllContextData(
            tos.getLogic()
               .storeAcceptedToS(new ContextDataFactoryImpl().fromInput(((UserPrincipal)this.principal.get()).user().getContextData()))
               .asKeyValueMap()
         );
   }

   private ContextData getContextData() {
      return this.contextDataFactory.fromPersistency(((UserPrincipal)this.principal.get()).user().getContextData());
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class AuthenticationTermsOfServiceServiceImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private SigningLogger signingLogger;
      @SuppressFBWarnings(justification = "generated code")
      private CommonTermsOfServiceService commonService;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<UserPrincipal> principal;
      @SuppressFBWarnings(justification = "generated code")
      private ContextDataFactory contextDataFactory;

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

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationTermsOfServiceServiceImpl.AuthenticationTermsOfServiceServiceImplBuilder signingLogger(SigningLogger signingLogger) {
         this.signingLogger = signingLogger;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationTermsOfServiceServiceImpl.AuthenticationTermsOfServiceServiceImplBuilder commonService(CommonTermsOfServiceService commonService) {
         this.commonService = commonService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationTermsOfServiceServiceImpl.AuthenticationTermsOfServiceServiceImplBuilder principal(Provider<UserPrincipal> principal) {
         this.principal = principal;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationTermsOfServiceServiceImpl.AuthenticationTermsOfServiceServiceImplBuilder contextDataFactory(ContextDataFactory contextDataFactory) {
         this.contextDataFactory = contextDataFactory;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AuthenticationTermsOfServiceServiceImpl build() {
         return new AuthenticationTermsOfServiceServiceImpl(this.signingLogger, this.commonService, this.principal, this.contextDataFactory);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "AuthenticationTermsOfServiceServiceImpl.AuthenticationTermsOfServiceServiceImplBuilder(signingLogger="
            + this.signingLogger
            + ", commonService="
            + this.commonService
            + ", principal="
            + this.principal
            + ", contextDataFactory="
            + this.contextDataFactory
            + ")";
      }
   }
}
