package com.airlock.iam.admin.infrastructure.metrics.license;

import com.airlock.iam.core.misc.util.config.ActiveLicenseEnvironment;
import com.airlock.iam.license.domain.model.date.LicenseDate;
import com.airlock.iam.plugin.framework.application.service.license.LicenseManager;
import com.google.common.annotations.VisibleForTesting;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import jakarta.inject.Inject;
import java.time.Instant;
import java.util.Date;
import java.util.function.Supplier;

public class LicenseMetrics {
   private final Supplier<LicenseManager> licenseManagerSupplier;

   @VisibleForTesting
   LicenseMetrics(Supplier<LicenseManager> licenseManagerSupplier, MeterRegistry registry) {
      this.licenseManagerSupplier = licenseManagerSupplier;
      Gauge.builder("iam.license.expiry.in", this::expiryInSeconds)
         .baseUnit("seconds")
         .description("The number of seconds in which the active license expires.")
         .register(registry);
      Gauge.builder("iam.license.valid.from.timestamp", this::notValidBeforeSeconds)
         .baseUnit("seconds")
         .description("Unix epoch time (seconds) at which the active license becomes valid.")
         .register(registry);
      Gauge.builder("iam.license.max.instances", this::instanceCount)
         .description("The maximum number of licensed instances on this system.")
         .register(registry);
      Gauge.builder("iam.license.max.users", this::userCount).description("The maximum number of licensed user on this system.").register(registry);
      Gauge.builder("iam.license.valid", this::isValid).description("Whether the license is valid (1) or not (0).").register(registry);
   }

   @Inject
   public LicenseMetrics(MeterRegistry registry) {
      this(ActiveLicenseEnvironment::activeLicenseManager, registry);
   }

   private int userCount() {
      return this.licenseManagerSupplier.get().getLicense().getNrOfLicensedUsers().orElse(0);
   }

   private int isValid() {
      return !this.isLicenseNotYetValid() && !this.isLicenseExpired() ? 1 : 0;
   }

   private int instanceCount() {
      return this.licenseManagerSupplier.get().getLicense().getNrOfLicensedInstances().orElse(0);
   }

   private long expiryInSeconds() {
      LicenseDate validUntil = this.licenseManagerSupplier.get().getLicense().getValidUntilDate();
      return validUntil == null ? 0L : validUntil.getDate().toInstant().getEpochSecond() - Instant.now().getEpochSecond();
   }

   private long notValidBeforeSeconds() {
      LicenseDate validFrom = this.licenseManagerSupplier.get().getLicense().getValidFromDate();
      return validFrom == null ? 0L : validFrom.getDate().toInstant().getEpochSecond();
   }

   private boolean isLicenseNotYetValid() {
      LicenseDate validFromDate = this.licenseManagerSupplier.get().getLicense().getValidFromDate();
      return validFromDate != null && validFromDate.isAfter(new Date());
   }

   private boolean isLicenseExpired() {
      LicenseDate validUntilDate = this.licenseManagerSupplier.get().getLicense().getValidUntilDate();
      return validUntilDate == null || validUntilDate.isBefore(new Date());
   }
}
