package com.airlock.iam.factor.application.service.airlock2fa;

import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FAAccountId;
import com.airlock.iam.base.api.domain.model.exception.EntityNotUniqueException;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAAccountDisplayName;
import com.airlock.iam.factor.domain.model.airlock2fa.order.Airlock2FAActivationLetterOrder;
import com.airlock.iam.factor.domain.model.airlock2fa.order.Airlock2FAActivationLetterOrderCreator;
import com.airlock.iam.factor.domain.service.airlock2fa.Airlock2FAAdminApiUserAccountService;
import com.airlock.iam.factor.domain.service.airlock2fa.activation.Airlock2FAActivationLetterOrderService;
import com.airlock.iam.log.api.signing.SigningLogger;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;
import lombok.NonNull;

public final class Airlock2FAAutoOrderService {
   private static final ELogger LOG = ELoggerFactory.getLogger(Airlock2FAAutoOrderService.class);
   @NonNull
   private final Airlock2FAAdminApiUserAccountService userCreateService;
   @NonNull
   private final Airlock2FAActivationLetterOrderService letterOrderService;
   @NonNull
   private final Airlock2FAActivationLetterOrderCreator orderCreator;
   @NonNull
   private final SigningLogger signingLogger;

   public Airlock2FAActivationLetterOrder createOrderForNewUser(UserId iamUserId, Optional<Airlock2FAAccountDisplayName> enrollmentDisplayName) {
      LOG.debug(String.format("Creating an Airlock 2FA account and activation letter order for new user '%s'", iamUserId));
      Airlock2FAAccountId accountId = this.createAirlock2FAAccount(iamUserId, enrollmentDisplayName);
      return this.createOrder(accountId);
   }

   private Airlock2FAActivationLetterOrder createOrder(Airlock2FAAccountId accountId) {
      Airlock2FAActivationLetterOrder order = this.letterOrderService
         .createOrder(accountId, this.orderCreator)
         .orElseThrow(() -> new EntityNotUniqueException(String.format("Airlock 2FA account ID '%s' already has an activation letter order", accountId)));
      this.signingLogger
         .log(String.format("Airlock 2FA activation letter order with ID '%s' automatically created for airlock 2FA account ID '%s'", order.getId(), accountId));
      return order;
   }

   private Airlock2FAAccountId createAirlock2FAAccount(UserId iamUserId, Optional<Airlock2FAAccountDisplayName> enrollmentDisplayName) {
      return this.userCreateService.createAccount(iamUserId, enrollmentDisplayName);
   }

   @SuppressFBWarnings(justification = "generated code")
   Airlock2FAAutoOrderService(
      @NonNull Airlock2FAAdminApiUserAccountService userCreateService,
      @NonNull Airlock2FAActivationLetterOrderService letterOrderService,
      @NonNull Airlock2FAActivationLetterOrderCreator orderCreator,
      @NonNull SigningLogger signingLogger
   ) {
      if (userCreateService == null) {
         throw new NullPointerException("userCreateService is marked non-null but is null");
      }

      if (letterOrderService == null) {
         throw new NullPointerException("letterOrderService is marked non-null but is null");
      }

      if (orderCreator == null) {
         throw new NullPointerException("orderCreator is marked non-null but is null");
      }

      if (signingLogger == null) {
         throw new NullPointerException("signingLogger is marked non-null but is null");
      }

      this.userCreateService = userCreateService;
      this.letterOrderService = letterOrderService;
      this.orderCreator = orderCreator;
      this.signingLogger = signingLogger;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class Airlock2FAAutoOrderServiceBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Airlock2FAAdminApiUserAccountService userCreateService;
      @SuppressFBWarnings(justification = "generated code")
      private Airlock2FAActivationLetterOrderService letterOrderService;
      @SuppressFBWarnings(justification = "generated code")
      private Airlock2FAActivationLetterOrderCreator orderCreator;
      @SuppressFBWarnings(justification = "generated code")
      private SigningLogger signingLogger;

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

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAAutoOrderService.Airlock2FAAutoOrderServiceBuilder userCreateService(@NonNull Airlock2FAAdminApiUserAccountService userCreateService) {
         if (userCreateService == null) {
            throw new NullPointerException("userCreateService is marked non-null but is null");
         }

         this.userCreateService = userCreateService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAAutoOrderService.Airlock2FAAutoOrderServiceBuilder letterOrderService(@NonNull Airlock2FAActivationLetterOrderService letterOrderService) {
         if (letterOrderService == null) {
            throw new NullPointerException("letterOrderService is marked non-null but is null");
         }

         this.letterOrderService = letterOrderService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAAutoOrderService.Airlock2FAAutoOrderServiceBuilder orderCreator(@NonNull Airlock2FAActivationLetterOrderCreator orderCreator) {
         if (orderCreator == null) {
            throw new NullPointerException("orderCreator is marked non-null but is null");
         }

         this.orderCreator = orderCreator;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAAutoOrderService.Airlock2FAAutoOrderServiceBuilder signingLogger(@NonNull SigningLogger signingLogger) {
         if (signingLogger == null) {
            throw new NullPointerException("signingLogger is marked non-null but is null");
         }

         this.signingLogger = signingLogger;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAAutoOrderService build() {
         return new Airlock2FAAutoOrderService(this.userCreateService, this.letterOrderService, this.orderCreator, this.signingLogger);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "Airlock2FAAutoOrderService.Airlock2FAAutoOrderServiceBuilder(userCreateService="
            + this.userCreateService
            + ", letterOrderService="
            + this.letterOrderService
            + ", orderCreator="
            + this.orderCreator
            + ", signingLogger="
            + this.signingLogger
            + ")";
      }
   }
}
