package com.airlock.iam.common.domain.model.mtan;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.core.misc.impl.authen.mtan.MtanHandler;
import com.airlock.iam.core.misc.impl.authen.mtan.MtanHandlerException;
import com.airlock.iam.core.misc.impl.token.MtanItem;
import com.airlock.iam.core.misc.renderer.SecretLetterRenderer;
import com.airlock.iam.core.misc.util.password.generator.PasswordRendererException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.Optional;

public class MtanItemBackedIak implements Iak {
   private final Optional<SecretLetterRenderer> letterRenderer;
   private final UserId userId;
   private final String admin;
   private final MtanItem mtanItem;
   private final MtanHandler mtanHandler;

   @Override
   public boolean isOrdered() {
      return this.mtanItem.hasBeenOrdered();
   }

   @Override
   public Optional<Date> getGenerationDate() {
      return this.mtanItem.getIAKLetterGenerationDate();
   }

   @Override
   public Optional<Date> getDeliveryDate() {
      return Optional.ofNullable(this.mtanItem.getDeliveryDate());
   }

   @Override
   public void generate() {
      SecretLetterRenderer renderer = this.letterRenderer.orElseThrow(() -> new FailureException("caller must ensure that letterRenderer is present"));

      try {
         String secret = this.mtanHandler.generateSecretAndStoreHashInToken(this.userId.getValue(), this.mtanItem);
         Date generationDate = new Date();
         this.mtanItem.setIAKLetterGenerationDate(generationDate);
         this.mtanItem.setDeliveryDate(generationDate);
         Map<String, Object> contextData = this.mtanHandler.getContextDataForIAKLetter(this.userId.getValue());
         renderer.renderSecretLetter(secret, this.userId.getValue(), this.admin, contextData, generationDate);
         this.mtanItem.resetOrder();
      } catch (MtanHandlerException | IOException | PasswordRendererException e) {
         throw new FailureException(String.format("Could not generate IAK letter for user '%s'", this.userId), e);
      }
   }

   @Override
   public void order() {
      this.mtanItem.order(this.admin);
   }

   @Override
   public void cancelOrder() {
      this.mtanItem.resetOrder();
   }

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

   @SuppressFBWarnings(justification = "generated code")
   private MtanItemBackedIak(Optional<SecretLetterRenderer> letterRenderer, UserId userId, String admin, MtanItem mtanItem, MtanHandler mtanHandler) {
      this.letterRenderer = letterRenderer;
      this.userId = userId;
      this.admin = admin;
      this.mtanItem = mtanItem;
      this.mtanHandler = mtanHandler;
   }

   @SuppressFBWarnings(justification = "generated code")
   public MtanItem getMtanItem() {
      return this.mtanItem;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class MtanItemBackedIakBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Optional<SecretLetterRenderer> letterRenderer;
      @SuppressFBWarnings(justification = "generated code")
      private UserId userId;
      @SuppressFBWarnings(justification = "generated code")
      private String admin;
      @SuppressFBWarnings(justification = "generated code")
      private MtanItem mtanItem;
      @SuppressFBWarnings(justification = "generated code")
      private MtanHandler mtanHandler;

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

      @SuppressFBWarnings(justification = "generated code")
      public MtanItemBackedIak.MtanItemBackedIakBuilder letterRenderer(Optional<SecretLetterRenderer> letterRenderer) {
         this.letterRenderer = letterRenderer;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanItemBackedIak.MtanItemBackedIakBuilder userId(UserId userId) {
         this.userId = userId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanItemBackedIak.MtanItemBackedIakBuilder admin(String admin) {
         this.admin = admin;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanItemBackedIak.MtanItemBackedIakBuilder mtanItem(MtanItem mtanItem) {
         this.mtanItem = mtanItem;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanItemBackedIak.MtanItemBackedIakBuilder mtanHandler(MtanHandler mtanHandler) {
         this.mtanHandler = mtanHandler;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanItemBackedIak build() {
         return new MtanItemBackedIak(this.letterRenderer, this.userId, this.admin, this.mtanItem, this.mtanHandler);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "MtanItemBackedIak.MtanItemBackedIakBuilder(letterRenderer="
            + this.letterRenderer
            + ", userId="
            + this.userId
            + ", admin="
            + this.admin
            + ", mtanItem="
            + this.mtanItem
            + ", mtanHandler="
            + this.mtanHandler
            + ")";
      }
   }
}
