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

import com.airlock.iam.base.misc.time.TimeProvider;
import com.airlock.iam.common.domain.model.state.PutResult;
import com.airlock.iam.common.domain.model.state.StateTimeout;
import com.airlock.iam.common.domain.service.state.StateRepository;
import com.airlock.iam.common.domain.service.state.StateRepositoryKey;
import com.airlock.iam.elog.api.EDefaultLogType;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.time.Duration;
import java.time.Instant;

public class DailyAnalyticsSubmissionCondition implements AnalyticsSubmissionCondition {
   private static final ELogger LOG = ELoggerFactory.getLogger(DailyAnalyticsSubmissionCondition.class);
   private static final StateRepositoryKey LATEST_SUBMISSION_KEY = new StateRepositoryKey("global", () -> "usage-analytics-latest-submission");
   private static final Duration SUBMISSION_INTERVAL = Duration.ofDays(1L);
   private final Provider<StateRepository> stateRepository;
   private final Provider<TimeProvider> time;

   @Inject
   public DailyAnalyticsSubmissionCondition(Provider<StateRepository> stateRepository, Provider<TimeProvider> time) {
      this.stateRepository = stateRepository;
      this.time = time;
   }

   @Override
   public boolean isSubmissionDue() {
      if (this.submittedRecently()) {
         return false;
      }

      String now = String.valueOf(((TimeProvider)this.time.get()).getCurrentInstant().getEpochSecond());
      PutResult putResult = ((StateRepository)this.stateRepository.get()).put(LATEST_SUBMISSION_KEY, now, StateTimeout.MAX_VALUE);
      if (!putResult.valueWasPut()) {
         LOG.warn(
            EDefaultLogType.GENERIC_LOG_TYPE,
            "Failed to put latest submission timestamp. This should never happen. This could lead to usage data being submitted more often than necessary."
         );
      }

      return true;
   }

   private boolean submittedRecently() {
      return ((StateRepository)this.stateRepository.get())
         .find(LATEST_SUBMISSION_KEY)
         .value()
         .map(rawInstant -> Instant.ofEpochSecond(Long.parseLong(rawInstant)))
         .map(latestSubmission -> latestSubmission.isAfter(((TimeProvider)this.time.get()).getCurrentInstant().minus(SUBMISSION_INTERVAL)))
         .orElse(false);
   }
}
