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

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FALogData;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAUser;
import com.airlock.iam.factor.domain.model.airlock2fa.activation.Airlock2FAActivationLetter;
import com.airlock.iam.factor.domain.model.airlock2fa.activation.Airlock2FAActivationLetterId;
import com.airlock.iam.factor.domain.model.airlock2fa.activation.Airlock2FAActivationSettings;
import com.airlock.iam.factor.domain.model.airlock2fa.enrollment.Airlock2FAEnrollment;
import com.airlock.iam.factor.domain.service.airlock2fa.Airlock2FAActivationLetterService;
import com.airlock.iam.factor.domain.service.airlock2fa.activation.Airlock2FAActivationLetterRepository;
import com.airlock.iam.factor.domain.service.airlock2fa.activation.LocalAirlock2FAActivationLetter;
import com.airlock.iam.factor.domain.service.airlock2fa.enrollment.Airlock2FAAdminApiEnrollmentService;
import com.airlock.iam.log.api.helpdesk.HelpdeskLogger;
import com.airlock.iam.log.api.signing.SigningLogger;
import jakarta.inject.Inject;
import lombok.NonNull;

public final class Airlock2FAActivationLetterServiceImpl implements Airlock2FAActivationLetterService {
   private static final ELogger LOG = ELoggerFactory.getLogger(Airlock2FAActivationLetterServiceImpl.class);
   private final Airlock2FAActivationLetterRepository repository;
   private final Airlock2FAAdminApiEnrollmentService enrollmentService;
   private final SigningLogger signingLogger;
   private final HelpdeskLogger helpdeskLogger;
   private final Airlock2FAActivationSettings activationSettings;

   @Inject
   public Airlock2FAActivationLetterServiceImpl(
      @NonNull Airlock2FAActivationLetterRepository repository,
      @NonNull Airlock2FAAdminApiEnrollmentService enrollmentService,
      SigningLogger signingLogger,
      HelpdeskLogger helpdeskLogger,
      Airlock2FAActivationSettings activationSettings
   ) {
      if (repository == null) {
         throw new NullPointerException("repository is marked non-null but is null");
      }

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

      this.repository = repository;
      this.enrollmentService = enrollmentService;
      this.signingLogger = signingLogger;
      this.helpdeskLogger = helpdeskLogger;
      this.activationSettings = activationSettings;
   }

   @Override
   public Airlock2FAActivationLetter create(Airlock2FAUser airlock2FAUser, UserId creator) {
      Airlock2FAAdminApiEnrollmentService.StartEnrollmentAnswer startEnrollmentAnswer = this.enrollmentService
         .startEnrollmentForExistingAccount(airlock2FAUser.getAccountId(), this.activationSettings);
      Airlock2FAEnrollment enrollment = this.enrollmentService
         .getEnrollment(startEnrollmentAnswer.getActivationCode())
         .orElseThrow(
            () -> new FailureException(
               String.format("Failed to fetch enrollment details for Airlock 2FA account ID \"%s\" created by \"%s\"", airlock2FAUser, creator)
            )
         );
      LocalAirlock2FAActivationLetter letter = new LocalAirlock2FAActivationLetter(
         Airlock2FAActivationLetterId.generateAirlock2FAActivationLetterId(), airlock2FAUser.getAccountId(), enrollment.getActivationCode(), creator
      );
      Airlock2FALogData logData = Airlock2FALogData.airlock2FALogData(airlock2FAUser.getAccountId()).withActivationSettings(this.activationSettings);
      UserId userId = airlock2FAUser.getIamUserId();
      this.signingLogger.log(String.format("Created a new Airlock 2FA activation letter for user %s %s", LogUtil.quote(userId), logData));
      this.helpdeskLogger
         .log(userId, String.format("Administrator ${authentee} created a new Airlock 2FA activation letter for user %s %s", LogUtil.quote(userId), logData));
      return Airlock2FAActivationLetter.airlock2FAActivationLetter(this.repository.insert(letter), enrollment);
   }

   @Override
   public boolean delete(Airlock2FAActivationLetter letter) {
      try {
         this.enrollmentService.deleteEnrollment(letter.getEnrollment().getActivationCode());
         this.repository.delete(letter.getId());
         return true;
      } catch (RuntimeException e) {
         LOG.info("Failed to delete Airlock 2FA activation letter: " + e.getMessage(), e);
         return false;
      }
   }
}
