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

import com.airlock.iam.base.api.domain.model.mapification.MapifiedValues;
import com.airlock.iam.base.domain.model.mapification.MapificationUtils;
import com.airlock.iam.base.domain.model.mapification.MapifiedValuesBuilder;
import com.airlock.iam.base.misc.data.OptionalString;
import com.airlock.iam.common.api.domain.model.phonenumber.PhoneNumber;
import com.airlock.iam.flow.shared.api.domain.model.session.ChangeDescriptionFlowAttribute;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;

public final class MtanTokenChangeDescription implements ChangeDescriptionFlowAttribute<MtanTokenChangeDescription> {
   private static final String EXISTING_TOKEN_KEY = "token";
   private static final String PHONE_NUMBER_KEY = "phone";
   private static final String LABEL_KEY = "label";
   private final Optional<SelectedMtanToken> existingToken;
   private final Optional<PhoneNumber> newPhoneNumber;
   private final OptionalString newLabel;

   public static MtanTokenChangeDescription emptyAttribute() {
      return emptyBuilder().build();
   }

   public static MtanTokenChangeDescription attributeForSelectedToken(SelectedMtanToken item) {
      return emptyBuilder().existingToken(Optional.of(item)).build();
   }

   public static MtanTokenChangeDescription attributeWithPhoneNumber(PhoneNumber phoneNumber) {
      return emptyBuilder().newPhoneNumber(Optional.of(phoneNumber)).build();
   }

   public static MtanTokenChangeDescription attributeWithLabel(String label) {
      return emptyBuilder().newLabel(OptionalString.of(label)).build();
   }

   public static MtanTokenChangeDescription removeLabel() {
      return emptyBuilder().newLabel(OptionalString.of(null)).build();
   }

   private static MtanTokenChangeDescription.MtanTokenChangeDescriptionBuilder emptyBuilder() {
      return builder().existingToken(Optional.empty()).newPhoneNumber(Optional.empty()).newLabel(OptionalString.none());
   }

   @Override
   public String description() {
      return "mTAN Token Change";
   }

   public MtanTokenChangeDescription mergeWith(MtanTokenChangeDescription newAttribute) {
      Optional<SelectedMtanToken> newExistingToken = newAttribute.getExistingToken().or(this::getExistingToken);
      Optional<PhoneNumber> newPhoneNumber = newAttribute.getNewPhoneNumber().or(this::getNewPhoneNumber);
      OptionalString newLabel = newAttribute.getNewLabel().hasValue() ? newAttribute.getNewLabel() : this.getNewLabel();
      return new MtanTokenChangeDescription(newExistingToken, newPhoneNumber, newLabel);
   }

   @Override
   public MapifiedValues mapify() {
      return MapifiedValuesBuilder.mapifiedValues()
         .putIfPresent("token", this.existingToken.map(SelectedMtanToken::mapify))
         .putIfPresent("phone", this.newPhoneNumber.map(PhoneNumber::getValue))
         .put("label", MapificationUtils.mapifyOptionalString(this.newLabel))
         .build();
   }

   public static MtanTokenChangeDescription demapify(MapifiedValues values) {
      return new MtanTokenChangeDescription(
         values.demapifyOptional("token", SelectedMtanToken::demapify),
         values.<String>getOptional("phone").map(PhoneNumber::phoneNumber),
         MapificationUtils.demapifyOptionalString(values.getValues("label"))
      );
   }

   @SuppressFBWarnings(justification = "generated code")
   MtanTokenChangeDescription(Optional<SelectedMtanToken> existingToken, Optional<PhoneNumber> newPhoneNumber, OptionalString newLabel) {
      this.existingToken = existingToken;
      this.newPhoneNumber = newPhoneNumber;
      this.newLabel = newLabel;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public Optional<SelectedMtanToken> getExistingToken() {
      return this.existingToken;
   }

   @SuppressFBWarnings(justification = "generated code")
   public Optional<PhoneNumber> getNewPhoneNumber() {
      return this.newPhoneNumber;
   }

   @SuppressFBWarnings(justification = "generated code")
   public OptionalString getNewLabel() {
      return this.newLabel;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class MtanTokenChangeDescriptionBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Optional<SelectedMtanToken> existingToken;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<PhoneNumber> newPhoneNumber;
      @SuppressFBWarnings(justification = "generated code")
      private OptionalString newLabel;

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

      @SuppressFBWarnings(justification = "generated code")
      public MtanTokenChangeDescription.MtanTokenChangeDescriptionBuilder existingToken(Optional<SelectedMtanToken> existingToken) {
         this.existingToken = existingToken;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanTokenChangeDescription.MtanTokenChangeDescriptionBuilder newPhoneNumber(Optional<PhoneNumber> newPhoneNumber) {
         this.newPhoneNumber = newPhoneNumber;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanTokenChangeDescription.MtanTokenChangeDescriptionBuilder newLabel(OptionalString newLabel) {
         this.newLabel = newLabel;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MtanTokenChangeDescription build() {
         return new MtanTokenChangeDescription(this.existingToken, this.newPhoneNumber, this.newLabel);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "MtanTokenChangeDescription.MtanTokenChangeDescriptionBuilder(existingToken="
            + this.existingToken
            + ", newPhoneNumber="
            + this.newPhoneNumber
            + ", newLabel="
            + this.newLabel
            + ")";
      }
   }
}
