package com.airlock.iam.admin.application.service.token.vasco;

import com.airlock.iam.admin.api.domain.model.administrator.CurrentAdministrator;
import com.airlock.iam.base.api.domain.model.exception.ServiceConfigurationException;
import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.base.api.domain.model.store.exception.StoreFailureException;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.api.domain.model.persistency.exception.PersisterException;
import com.airlock.iam.core.misc.impl.persistency.token.TokenStatistics;
import com.airlock.iam.core.misc.impl.token.VascoToken;
import com.airlock.iam.core.misc.impl.token.VascoToken.AuthenticationMode;
import com.airlock.iam.core.misc.persistency.token.TokenDataProvider;
import com.airlock.iam.core.misc.util.vasco.VascoException;
import com.airlock.iam.log.api.signing.SigningLogger;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class VascoLicenseService {
   private final Map<AuthenticationMode, VascoLicenseSettings> settings;
   private final CurrentAdministrator admin;
   private final SigningLogger signingLogger;

   @Inject
   public VascoLicenseService(Map<AuthenticationMode, VascoLicenseSettings> settings, CurrentAdministrator admin, SigningLogger signingLogger) {
      this.settings = settings;
      this.admin = admin;
      this.signingLogger = signingLogger;
   }

   public List<String> importLicenseFile(File licenseFile, String licenseKey, Optional<String> softwareVector, AuthenticationMode expectedMode) {
      List<String> importedIds = this.importLicense(licenseFile, licenseKey, softwareVector, expectedMode);
      this.logAdminAction("imported Vasco license file with " + importedIds.size() + " tokens of type " + expectedMode);
      return importedIds;
   }

   public List<String> importLicenseWithoutFile(String licenseKey, Optional<String> softwareVector, AuthenticationMode expectedMode) {
      List<String> importedIds = this.importLicense(null, licenseKey, softwareVector, expectedMode);
      this.logAdminAction("imported " + importedIds + " Vasco tokens of type " + expectedMode);
      return importedIds;
   }

   private List<String> importLicense(@Nullable File licenseFile, String licenseKey, Optional<String> softwareVector, AuthenticationMode expectedMode) {
      VascoLicenseSettings typeSettings = (VascoLicenseSettings)ServiceConfigurationException.checkNotNull(this.settings.get(expectedMode));

      try {
         VascoLicenseImportCallback callback = this.createCallback(expectedMode, typeSettings);
         return typeSettings.getVascoHandler().importTokensFromFile(licenseFile, licenseKey, softwareVector, callback);
      } catch (VascoException e) {
         throw new ViolationException(e);
      }
   }

   private VascoLicenseImportCallback createCallback(AuthenticationMode expectedMode, VascoLicenseSettings typeSettings) {
      return VascoLicenseImportCallback.builder()
         .expectedAuthMode(Optional.of(expectedMode))
         .enableImportedTokens(typeSettings.isEnableImportedTokens())
         .tokenDataProvider(typeSettings.getTokenDataProvider())
         .vascoHandler(typeSettings.getVascoHandler())
         .build();
   }

   public VascoLicenseInfo getLicenseInfo(AuthenticationMode authMode) {
      VascoLicenseSettings typeSettings = (VascoLicenseSettings)ServiceConfigurationException.checkNotNull(this.settings.get(authMode));
      TokenDataProvider tdp = typeSettings.getTokenDataProvider();
      TokenStatistics statistics = this.getStatistics(tdp, authMode);
      return VascoLicenseInfo.builder()
         .assignedActive(statistics.assignedActive())
         .assignedInactive(statistics.assignedInactive())
         .unassignedActive(statistics.unusedActive())
         .unassignedInactive(statistics.unusedInactive())
         .build();
   }

   private TokenStatistics getStatistics(TokenDataProvider tdp, AuthenticationMode authMode) {
      try {
         return tdp.getStatistics(VascoToken.getAuthenticationModeFilter(authMode));
      } catch (PersisterException e) {
         throw new StoreFailureException(e);
      }
   }

   private void logAdminAction(String actionDesc) {
      this.signingLogger.log("Admin " + LogUtil.quote(this.admin.getName()) + " " + actionDesc);
   }

   @SuppressFBWarnings(justification = "generated code")
   public static VascoLicenseService.VascoLicenseServiceBuilder builder() {
      return new VascoLicenseService.VascoLicenseServiceBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class VascoLicenseServiceBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Map<AuthenticationMode, VascoLicenseSettings> settings;
      @SuppressFBWarnings(justification = "generated code")
      private CurrentAdministrator admin;
      @SuppressFBWarnings(justification = "generated code")
      private SigningLogger signingLogger;

      @SuppressFBWarnings(justification = "generated code")
      VascoLicenseServiceBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public VascoLicenseService.VascoLicenseServiceBuilder settings(Map<AuthenticationMode, VascoLicenseSettings> settings) {
         this.settings = settings;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public VascoLicenseService.VascoLicenseServiceBuilder admin(CurrentAdministrator admin) {
         this.admin = admin;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public VascoLicenseService.VascoLicenseServiceBuilder signingLogger(SigningLogger signingLogger) {
         this.signingLogger = signingLogger;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public VascoLicenseService build() {
         return new VascoLicenseService(this.settings, this.admin, this.signingLogger);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "VascoLicenseService.VascoLicenseServiceBuilder(settings="
            + this.settings
            + ", admin="
            + this.admin
            + ", signingLogger="
            + this.signingLogger
            + ")";
      }
   }
}
