package com.airlock.iam.oauth2.domain.service.persistence;

import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.api.domain.model.persistency.exception.NotFoundException;
import com.airlock.iam.common.api.domain.model.persistency.exception.PersisterException;
import com.airlock.iam.core.misc.persistency.token.TokenBean;
import com.airlock.iam.core.misc.persistency.token.TokenDataProvider;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.oauth2.api.domain.model.AuthorizationServerId;
import com.airlock.iam.oauth2.domain.model.token.AbstractTokenTableOAuth2Token;
import com.airlock.iam.oauth2.domain.model.token.OAuth2Token;
import com.airlock.iam.oauth2.domain.service.OAuth2GrantsSessionService;
import com.airlock.iam.oauth2.domain.service.OAuth2TokenFilterFactory;
import com.airlock.iam.plugin.api.config.LogTypes;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.List;
import java.util.function.Supplier;
import lombok.NonNull;

public class OAuth2TokenDeleter {
   @NonNull
   private final TokenDataProvider tokenDataProvider;
   @NonNull
   private final Supplier<OAuth2GrantsSessionService> sessionService;
   @NonNull
   private final ELogger logger;
   @NonNull
   private final AuthorizationServerId authorizationServerId;

   public void purgeRelatedTokensFromDatabase(OAuth2Token token) throws PersisterException {
      List<TokenBean> tokensToDelete = this.getRelatedTokens(token);

      try {
         this.logger
            .warn(
               LogTypes.PLUGIN_INFO,
               "Deleting affected OAuth 2.0 Tokens of user "
                  + LogUtil.quote(token.getUserId())
                  + " for OAuth 2.0 client "
                  + LogUtil.quote(token.getClientId())
                  + " due to (possibly) compromised "
                  + token.getOAuth2TokenSubtype()
                  + ". "
                  + tokensToDelete.size()
                  + " OAuth 2.0 Token(s) will be deleted."
            );
      } catch (RuntimeException e) {
         this.logger
            .warn(
               LogTypes.PLUGIN_INFO,
               "Deleting affected OAuth 2.0 Tokens for OAuth 2.0 client "
                  + LogUtil.quote(token.getClientId())
                  + " due to (possibly) compromised "
                  + token.getOAuth2TokenSubtype()
                  + ". "
                  + tokensToDelete.size()
                  + " OAuth 2.0 Token(s) will be deleted."
            );
      }

      for (TokenBean tokenToDelete : tokensToDelete) {
         this.removeToken(tokenToDelete);
      }

      this.sessionService.get().deleteOAuth2Session(token.getSessionId());
   }

   public void removeToken(OAuth2Token token) throws PersisterException {
      this.removeToken(AbstractTokenTableOAuth2Token.asTokenTableBasedOAuth2Token(token).getDelegate());
   }

   private void removeToken(TokenBean delegate) throws PersisterException {
      try {
         this.tokenDataProvider.removeToken(delegate);
      } catch (NotFoundException var3) {
      }
   }

   private List<TokenBean> getRelatedTokens(OAuth2Token token) throws PersisterException {
      TokenDataProvider.TokenFilter filter = OAuth2TokenFilterFactory.oAuth2TokenFilterForAs(this.authorizationServerId)
         .filterGenericDataElement6(token.getSessionId().getId());
      return this.tokenDataProvider.get(filter);
   }

   @SuppressFBWarnings(justification = "generated code")
   public OAuth2TokenDeleter(
      @NonNull TokenDataProvider tokenDataProvider,
      @NonNull Supplier<OAuth2GrantsSessionService> sessionService,
      @NonNull ELogger logger,
      @NonNull AuthorizationServerId authorizationServerId
   ) {
      if (tokenDataProvider == null) {
         throw new NullPointerException("tokenDataProvider is marked non-null but is null");
      }

      if (sessionService == null) {
         throw new NullPointerException("sessionService is marked non-null but is null");
      }

      if (logger == null) {
         throw new NullPointerException("logger is marked non-null but is null");
      }

      if (authorizationServerId == null) {
         throw new NullPointerException("authorizationServerId is marked non-null but is null");
      }

      this.tokenDataProvider = tokenDataProvider;
      this.sessionService = sessionService;
      this.logger = logger;
      this.authorizationServerId = authorizationServerId;
   }
}
