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

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.common.api.domain.model.user.UserIdentity;
import com.airlock.iam.common.domain.model.user.PrincipalInfo;
import com.airlock.iam.core.misc.authen.result.AuthenticationFailed;
import com.airlock.iam.core.misc.impl.token.MtanItem;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import java.util.Date;
import java.util.List;
import java.util.Optional;

public class UserPrincipalWithMtan {
   private final PrincipalInfo principal;
   private final MtanTokens mtanTokens;

   @Inject
   public UserPrincipalWithMtan(PrincipalInfo principal, MtanTokens mtanTokens) {
      this.principal = principal;
      this.mtanTokens = mtanTokens;
   }

   public List<AuthenticationFailed.MtanChoiceToken> getMtanTokenChoices() {
      return this.mtanTokens.createChoicesForAuthentication(this.userId());
   }

   public Optional<AuthenticationFailed.MtanChoiceToken> getMostRecentChoice() {
      return this.mtanTokens.getMostRecentChoice(this.userId());
   }

   public String getName() {
      return this.userId().getValue();
   }

   public Optional<MtanItem> getMtanTokenById(String id) {
      return this.mtanTokens.findMtanToken(this.userId(), id);
   }

   public void markLastChoiceAsUsed(AuthenticationFailed.MtanChoiceToken choice) {
      Optional<MtanItem> mtan = this.getMtanTokenById(choice.getId());
      ViolationException.checkPresent(mtan, String.format("Could not find an mTAN token with ID '%s' for user '%s'", choice.getId(), this.getName()));
      mtan.get().handleLatestUsage(new Date());
      this.mtanTokens.store(this.userId(), mtan.get());
   }

   private UserId userId() {
      return this.principal.getKnownIdentity().map(UserIdentity::id).orElseThrow(() -> new FailureException("Principal must have a known identity"));
   }

   @SuppressFBWarnings(justification = "generated code")
   public PrincipalInfo getPrincipal() {
      return this.principal;
   }
}
