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

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
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.flow.api.domain.model.step.StepSession;
import java.util.Optional;
import lombok.NonNull;

public final class DeviceTokenAuthStepSession implements StepSession {
   private static final String TOKEN_ID_KEY = "tokenId";
   private static final String CHALLENGE_KEY = "challenge";
   private static final String VALID_TO_KEY = "validTo";
   private Optional<DeviceTokenChallenge> challenge = Optional.empty();

   public void setChallenge(@NonNull DeviceTokenChallenge newChallenge) {
      if (newChallenge == null) {
         throw new NullPointerException("newChallenge is marked non-null but is null");
      }

      if (this.challenge.isPresent()) {
         throw new ViolationException("Already created a challenge for device token step session.");
      }

      this.challenge = Optional.of(newChallenge);
   }

   public DeviceTokenChallenge retrieveChallenge() {
      ViolationException.checkPresent(this.challenge, "No challenge present in device token step session.");
      DeviceTokenChallenge challengeToReturn = this.challenge.get();
      this.challenge = Optional.empty();
      return challengeToReturn;
   }

   public boolean isExpectingVerification() {
      return this.challenge.isPresent();
   }

   @Override
   public MapifiedValues mapify() {
      return this.challenge.isEmpty()
         ? new MapifiedValues()
         : MapifiedValuesBuilder.mapifiedValues()
            .put("tokenId", this.challenge.get().getDeviceTokenId())
            .put("challenge", this.challenge.get().getChallenge())
            .put("validTo", MapificationUtils.mapifyInstant(this.challenge.get().getValidTo()))
            .build();
   }

   public static DeviceTokenAuthStepSession demapify(MapifiedValues values) {
      DeviceTokenAuthStepSession session = new DeviceTokenAuthStepSession();
      if (!values.containsKey("challenge")) {
         return session;
      }

      DeviceTokenChallenge challenge = new DeviceTokenChallenge(
         values.get("tokenId"), values.get("challenge"), values.demapifyValue("validTo", MapificationUtils::demapifyInstant)
      );
      session.setChallenge(challenge);
      return session;
   }
}
