package com.airlock.iam.admin.infrastructure.service.analytics;

import com.airlock.iam.admin.application.service.analytics.AnalyticsAccessTokenService;
import com.airlock.iam.admin.application.service.analytics.AnalyticsReportingLevel;
import com.airlock.iam.admin.application.service.analytics.AnalyticsService;
import com.airlock.iam.admin.application.service.analytics.AnalyticsSubmissionCondition;
import com.airlock.iam.admin.domain.model.analytics.Analytics;
import com.airlock.iam.admin.domain.model.analytics.AnalyticsAuthKey;
import com.airlock.iam.admin.domain.model.analytics.AnalyticsWrappingKey;
import com.airlock.iam.admin.domain.model.analytics.EncryptedAnalytics;
import com.airlock.iam.admin.infrastructure.mapper.analytics.AnalyticsMapper;
import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;
import java.util.Optional;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

public class AnalyticsSubmissionService {
   private static final ELogger LOG = ELoggerFactory.getLogger(AnalyticsSubmissionService.class);
   static final AnalyticsWrappingKey PROD_PUBLIC_WRAPPING_KEY = new AnalyticsWrappingKey(readPublicKeyFromFile());
   static final AnalyticsAuthKey PROD_AUTH_KEY = new AnalyticsAuthKey("3C/ZZiRu9jtq7ed7LmLAByAlg0ufby8jaXzfDBrf5K8=");
   private final Provider<AnalyticsService> dataService;
   private final Provider<AnalyticsEncryptionService> encryption;
   private final Provider<AnalyticsAccessTokenService> accessTokenService;
   private final Provider<AnalyticsReportingLevel> reportingLevel;
   private final Provider<AnalyticsSubmissionCondition> condition;
   private final Provider<AnalyticsPrintingService> printingService;
   private final Provider<AnalyticsMapper> usageDataMapper;

   @Inject
   public AnalyticsSubmissionService(
      Provider<AnalyticsService> dataService,
      Provider<AnalyticsEncryptionService> encryption,
      Provider<AnalyticsAccessTokenService> accessTokenService,
      Provider<AnalyticsReportingLevel> reportingLevel,
      Provider<AnalyticsSubmissionCondition> condition,
      Provider<AnalyticsPrintingService> printingService,
      Provider<AnalyticsMapper> usageDataMapper
   ) {
      this.dataService = dataService;
      this.encryption = encryption;
      this.accessTokenService = accessTokenService;
      this.reportingLevel = reportingLevel;
      this.condition = condition;
      this.printingService = printingService;
      this.usageDataMapper = usageDataMapper;
   }

   public Optional<AnalyticsSubmission> analyticsSubmission() {
      if (((AnalyticsReportingLevel)this.reportingLevel.get()).isDisabled()) {
         LOG.debug("Analytics is disabled because the active license does not permit it.");
         return Optional.empty();
      } else if (!((AnalyticsSubmissionCondition)this.condition.get()).isSubmissionDue()) {
         LOG.debug("Analytics data is currently not due for submission.");
         return Optional.empty();
      } else {
         Analytics analytics = ((AnalyticsService)this.dataService.get()).getAnalytics();
         String data = ((AnalyticsMapper)this.usageDataMapper.get()).map(analytics).toJsonString();
         LOG.info("Successfully collected latest analytics data.");
         ((AnalyticsPrintingService)this.printingService.get()).printToFile(data);
         EncryptedAnalytics encryptedData = ((AnalyticsEncryptionService)this.encryption.get()).encrypt(data, PROD_PUBLIC_WRAPPING_KEY);
         AnalyticsSubmission submission = new AnalyticsSubmission(
            encryptedData, ((AnalyticsAccessTokenService)this.accessTokenService.get()).generateAccessToken(PROD_AUTH_KEY)
         );
         return Optional.of(submission);
      }
   }

   private static PublicKey readPublicKeyFromFile() {
      try (InputStream is = AnalyticsSubmissionService.class.getResourceAsStream("analytics-encryption-public-key.pem")) {
         PemReader pemReader = new PemReader(new InputStreamReader(Objects.requireNonNull(is), StandardCharsets.UTF_8));

         PublicKey var5;
         try {
            PemObject pemObject = pemReader.readPemObject();
            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pemObject.getContent());
            KeyFactory factory = KeyFactory.getInstance("RSA");
            var5 = factory.generatePublic(pubKeySpec);
         } catch (Throwable var8) {
            try {
               pemReader.close();
            } catch (Throwable var7) {
               var8.addSuppressed(var7);
            }

            throw var8;
         }

         pemReader.close();
         return var5;
      } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
         throw new FailureException(e);
      }
   }
}
