package com.airlock.iam.servicecontainer.app.infrastructure.airlock2fa;

import com.airlock.iam.base.misc.time.RealTimeProvider;
import com.airlock.iam.base.misc.time.TimeProvider;
import com.airlock.iam.common.domain.model.jwt.JwtSecret;
import com.airlock.iam.common.domain.service.jwt.JwtHmacAndAesGcmEncryptionImpl;
import com.airlock.iam.common.infrastructure.logger.RestHelpdeskLogger;
import com.airlock.iam.core.domain.service.jwt.JwtHmacAndAesGcmEncryption;
import com.airlock.iam.core.infrastructure.IamSigningLogger;
import com.airlock.iam.database.infrastructure.JooqConfig;
import com.airlock.iam.factor.domain.model.airlock2fa.activation.Airlock2FAActivationSettings;
import com.airlock.iam.factor.domain.service.airlock2fa.Airlock2FAActivationLetterOrderServiceImpl;
import com.airlock.iam.factor.domain.service.airlock2fa.Airlock2FAActivationLetterPrintingService;
import com.airlock.iam.factor.domain.service.airlock2fa.Airlock2FAActivationLetterService;
import com.airlock.iam.factor.domain.service.airlock2fa.Airlock2FAAdminApiUserService;
import com.airlock.iam.factor.domain.service.airlock2fa.QrCodeImageReader;
import com.airlock.iam.factor.domain.service.airlock2fa.activation.Airlock2FAActivationCodeMapper;
import com.airlock.iam.factor.domain.service.airlock2fa.activation.Airlock2FAActivationLetterOrderService;
import com.airlock.iam.factor.domain.service.airlock2fa.activation.Airlock2FAActivationLetterRepository;
import com.airlock.iam.factor.domain.service.airlock2fa.enrollment.Airlock2FAAdminApiEnrollmentService;
import com.airlock.iam.factor.domain.service.airlock2fa.repository.Airlock2FAActivationLetterOrderRepository;
import com.airlock.iam.factor.domain.service.airlock2fa.repository.Airlock2FAUserRepository;
import com.airlock.iam.factor.infrastructure.repository.airlock2fa.Airlock2FAActivationCodeMapperImpl;
import com.airlock.iam.factor.infrastructure.repository.airlock2fa.Airlock2FAActivationLetterOrderRepositoryImpl;
import com.airlock.iam.factor.infrastructure.repository.airlock2fa.Airlock2FAActivationLetterRepositoryImpl;
import com.airlock.iam.factor.infrastructure.repository.airlock2fa.Airlock2FAUserRepositoryImpl;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.FuturaeAdminApiEnrollmentRequestFactory;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.FuturaeAdminApiEnrollmentServiceImpl;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.FuturaeAdminApiRequestFactoryImpl;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.FuturaeRequestFactory;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.QrCodeImageReaderImpl;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.header.FuturaeAuthenticationDataFactory;
import com.airlock.iam.factor.infrastructure.service.airlock2fa.Airlock2FAActivationLetterPrintingServiceImpl;
import com.airlock.iam.factor.infrastructure.service.airlock2fa.Airlock2FAActivationLetterServiceImpl;
import com.airlock.iam.factor.infrastructure.service.airlock2fa.FuturaeAdminApiUserServiceImpl;
import com.airlock.iam.log.processor.NopLogMessageProcessor;
import com.airlock.iam.servicecontainer.app.application.configuration.task.airlock2fa.Airlock2FAActivationLetterOrderTaskConfig;
import com.airlock.iam.servicecontainer.app.domain.model.task.airlock2fa.Airlock2FAActivationLetterOrderTask;
import com.airlock.iam.servicecontainer.app.domain.service.airlock2fa.Airlock2FAActivationLetterOrderTaskService;
import jakarta.inject.Provider;
import java.io.File;
import java.util.Optional;

public final class Airlock2FAActivationLetterOrderTaskFactory {
   public static Airlock2FAActivationLetterOrderTask airlock2FAActivationLetterOrderTask(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new Airlock2FAActivationLetterOrderTask(orderService(config), taskService(config));
   }

   private static Airlock2FAActivationLetterOrderService orderService(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new Airlock2FAActivationLetterOrderServiceImpl(orderRepository(config), Airlock2FAActivationLetterOrderTaskFactory::timeProvider);
   }

   private static Provider<Airlock2FAActivationLetterOrderRepository> orderRepository(Airlock2FAActivationLetterOrderTaskConfig config) {
      return () -> new Airlock2FAActivationLetterOrderRepositoryImpl(jooqConfig(config));
   }

   private static JooqConfig jooqConfig(Airlock2FAActivationLetterOrderTaskConfig config) {
      return config.getAirlock2faSettings().getRepository().jooqConfig();
   }

   private static TimeProvider timeProvider() {
      return new RealTimeProvider();
   }

   private static Airlock2FAActivationLetterOrderTaskService taskService(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new Airlock2FAActivationLetterOrderTaskService(
         userRepository(config), userService(config), activationLetterService(config), activationLetterPrintingService(config), new IamSigningLogger()
      );
   }

   private static Airlock2FAActivationSettings activationSettings(Airlock2FAActivationLetterOrderTaskConfig config) {
      return Airlock2FAActivationSettings.builder()
         .enrollmentTimeout(config.getEnrollmentValidity())
         .recoveryFlowBindingEnabled(config.getAirlock2faSettings().isTrustedSessionBindingForRecovery())
         .activationFlowBindingEnabled(config.getAirlock2faSettings().getTrustedSessionBindingForActivation().isEnabledForLetters())
         .provideActivationCodeShortEnabled(false)
         .build();
   }

   private static Airlock2FAAdminApiUserService userService(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new FuturaeAdminApiUserServiceImpl(
         config.getAirlock2faSettings().getFuturaeServer().getRestClient(),
         new FuturaeAdminApiRequestFactoryImpl(
            new FuturaeRequestFactory(
               FuturaeAuthenticationDataFactory.createFuturaeAdminAuthenticationData(config.getAirlock2faSettings().getFuturaeServer()), timeProvider()
            )
         )
      );
   }

   private static Airlock2FAAdminApiEnrollmentService enrollmentService(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new FuturaeAdminApiEnrollmentServiceImpl(
         config.getAirlock2faSettings().getFuturaeServer().getRestClient(),
         new FuturaeAdminApiEnrollmentRequestFactory(
            new FuturaeRequestFactory(
               FuturaeAuthenticationDataFactory.createFuturaeAdminAuthenticationData(config.getAirlock2faSettings().getFuturaeServer()), timeProvider()
            )
         )
      );
   }

   private static Airlock2FAUserRepository userRepository(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new Airlock2FAUserRepositoryImpl(jooqConfig(config));
   }

   private static Airlock2FAActivationLetterService activationLetterService(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new Airlock2FAActivationLetterServiceImpl(
         activationLetterRepository(config),
         enrollmentService(config),
         new IamSigningLogger(),
         new RestHelpdeskLogger(() -> "Service Container", NopLogMessageProcessor::new),
         activationSettings(config)
      );
   }

   private static Airlock2FAActivationLetterRepository activationLetterRepository(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new Airlock2FAActivationLetterRepositoryImpl(jooqConfig(config), activationCodeMapper(config));
   }

   private static Airlock2FAActivationCodeMapper activationCodeMapper(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new Airlock2FAActivationCodeMapperImpl(hmacAndAesGcmEncryption(config));
   }

   private static JwtHmacAndAesGcmEncryption hmacAndAesGcmEncryption(Airlock2FAActivationLetterOrderTaskConfig config) {
      JwtSecret jwtSecret = config.getAirlock2faSettings().getRepository().getStorageEncryptionConfig().getJwtSecret();
      return new JwtHmacAndAesGcmEncryptionImpl(jwtSecret.getJwtKeys());
   }

   private static Airlock2FAActivationLetterPrintingService activationLetterPrintingService(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new Airlock2FAActivationLetterPrintingServiceImpl(
         userId -> config.getUserStore().getByIdentity(userId).getContextData(),
         qrCodeImageReader(config),
         config.getRenderer(),
         config.getOutputDirectory().toPath(),
         Optional.ofNullable(config.getWorkingDirectory()).map(File::toPath),
         Optional.ofNullable(config.getLanguageContextDataName())
      );
   }

   private static QrCodeImageReader qrCodeImageReader(Airlock2FAActivationLetterOrderTaskConfig config) {
      return new QrCodeImageReaderImpl(config.getAirlock2faSettings().getFuturaeServer());
   }

   private Airlock2FAActivationLetterOrderTaskFactory() {
      throw new AssertionError();
   }
}
