package com.airlock.iam.common.infrastructure.sso;

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.infrastructure.db.DbInstantConverter;
import com.airlock.iam.base.misc.time.TimeProvider;
import com.airlock.iam.common.application.configuration.sso.PersistentAcceptedSsoTicketRepositoryConfig;
import com.airlock.iam.common.domain.service.sso.PersistentAcceptedSsoTicketRepository;
import com.airlock.iam.core.infrastructure.db.JooqProvider;
import com.airlock.iam.database.infrastructure.JooqConfig;
import com.airlock.iam.database.infrastructure.TenantId;
import com.airlock.iam.database.infrastructure.generated.schema.Tables;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import jakarta.inject.Inject;
import java.time.Instant;
import org.jooq.DSLContext;

@LogicForConfig(PersistentAcceptedSsoTicketRepositoryConfig.class)
public final class PersistentAcceptedSsoTicketRepositoryImpl implements PersistentAcceptedSsoTicketRepository {
   private static final ELogger LOG = ELoggerFactory.getLogger(PersistentAcceptedSsoTicketRepositoryImpl.class);
   private final DSLContext jooqDslProvider;
   private final TenantId tenantId;
   private final TimeProvider timeProvider;

   @Inject
   public PersistentAcceptedSsoTicketRepositoryImpl(JooqConfig jooqConfig, TimeProvider timeProvider) {
      this.jooqDslProvider = JooqProvider.jooqProvider(jooqConfig).db();
      this.tenantId = jooqConfig.tenantId();
      this.timeProvider = timeProvider;
   }

   @Override
   public boolean containsAcceptedTicket(String ssoTicketId) {
      return this.jooqDslProvider
         .fetchExists(
            this.jooqDslProvider
               .selectFrom(Tables.ACCEPTED_SSO_TICKETS)
               .where(Tables.ACCEPTED_SSO_TICKETS.TICKET_ID.eq(ssoTicketId).and(Tables.ACCEPTED_SSO_TICKETS.TENANT_ID.eq(this.tenantId.tenantId())))
         );
   }

   @Override
   public void storeAcceptedTicket(String ssoTicketId, Instant expirationDate) {
      this.jooqDslProvider
         .insertInto(Tables.ACCEPTED_SSO_TICKETS)
         .columns(Tables.ACCEPTED_SSO_TICKETS.TICKET_ID, Tables.ACCEPTED_SSO_TICKETS.EXPIRES_AT, Tables.ACCEPTED_SSO_TICKETS.TENANT_ID)
         .values(ssoTicketId, DbInstantConverter.toNanoSecondsSinceEpoch(expirationDate), this.tenantId.tenantId())
         .execute();
      LOG.debug("Stored accepted SSO ticket with ID: \"" + ssoTicketId + "\"");
   }

   @Override
   public int countExpiredSsoTickets() {
      return this.jooqDslProvider
         .fetchCount(
            Tables.ACCEPTED_SSO_TICKETS,
            Tables.ACCEPTED_SSO_TICKETS.EXPIRES_AT.lessOrEqual(DbInstantConverter.toNanoSecondsSinceEpoch(this.timeProvider.getCurrentInstant()))
         );
   }

   @Override
   public int removeExpiredSsoTicketsBatch(int batchSize) {
      int numDeleted = this.jooqDslProvider
         .deleteFrom(Tables.ACCEPTED_SSO_TICKETS)
         .where(Tables.ACCEPTED_SSO_TICKETS.EXPIRES_AT.lessOrEqual(DbInstantConverter.toNanoSecondsSinceEpoch(this.timeProvider.getCurrentInstant())))
         .limit(batchSize)
         .execute();
      LOG.debug("Deleted " + numDeleted + " expired SSO tickets from the database.");
      return numDeleted;
   }
}
