package com.airlock.iam.authentication.domain.model.airlock2fa;

import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FADeviceId;
import com.airlock.iam.common.api.domain.model.user.UserIdentity;
import com.airlock.iam.common.domain.model.user.PrincipalInfo;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAAuthDevice;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FADevices;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAPreAuthenticationData;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FARegisteredDevice;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAUser;
import com.airlock.iam.factor.domain.service.airlock2fa.Airlock2FAPreAuthenticationService;
import com.airlock.iam.factor.domain.service.airlock2fa.repository.Airlock2FAUserRepository;
import com.airlock.iam.flow.shared.domain.model.airlock2fa.Airlock2FAActivationStepSkipCheck;
import jakarta.inject.Inject;
import java.util.Optional;
import java.util.stream.Collectors;

public final class ActivationStepSkipCheckForAuthFlow implements Airlock2FAActivationStepSkipCheck {
   private static final ELogger LOG = ELoggerFactory.getLogger(ActivationStepSkipCheckForAuthFlow.class);
   private final Airlock2FAPreAuthenticationService preAuthService;
   private final Airlock2FAUserRepository repository;
   private final PrincipalInfo principalInfo;

   @Inject
   public ActivationStepSkipCheckForAuthFlow(
      Airlock2FAPreAuthenticationService preAuthService, Airlock2FAUserRepository repository, PrincipalInfo principalInfo
   ) {
      this.preAuthService = preAuthService;
      this.repository = repository;
      this.principalInfo = principalInfo;
   }

   @Override
   public Optional<Airlock2FARegisteredDevice> shouldSkipActivation() {
      UserIdentity userIdentity = this.principalInfo.getKnownIdentity().orElseThrow();
      Optional<Airlock2FAUser> airlock2FAAccount = this.repository.findBy(userIdentity.id());
      if (airlock2FAAccount.isEmpty()) {
         return Optional.empty();
      }

      Airlock2FADevices devices = this.preAuthService
         .preAuthenticate(new Airlock2FAPreAuthenticationData(airlock2FAAccount.get().getAccountId(), userIdentity.providedUsername().getValue()))
         .getDevices();
      if (devices.isEmpty()) {
         return Optional.empty();
      }

      if (devices.size() != 1) {
         LOG.info("Expected exactly one device but got " + devices.size() + ": " + commaseperatedIds(devices));
      }

      return devices.firstDevice()
         .map(Airlock2FAAuthDevice::getId)
         .map(id -> Airlock2FARegisteredDevice.registeredDevice(id, airlock2FAAccount.get().getAccountId()));
   }

   private static String commaseperatedIds(Airlock2FADevices devices) {
      return devices.stream().map(Airlock2FAAuthDevice::getId).<CharSequence>map(Airlock2FADeviceId::getId).collect(Collectors.joining(", "));
   }
}
