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

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.common.api.domain.model.persistency.exception.PersisterException;
import com.airlock.iam.core.misc.persistency.token.TokenDataProvider;
import com.airlock.iam.core.misc.util.DateRange;
import com.airlock.iam.oauth2.api.domain.model.OAuth2Scope;
import com.airlock.iam.oauth2.domain.model.token.AbstractTokenTableOAuth2Token;
import com.airlock.iam.oauth2.domain.model.token.OAuth2RefreshToken;
import com.airlock.iam.oauth2.domain.model.token.OAuth2Token;
import com.airlock.iam.oauth2.domain.model.token.OAuth2TokenTableRefreshToken;
import com.airlock.iam.oauth2.domain.model.token.OpenIDConnectIDToken;
import com.airlock.iam.oauth2.domain.model.token.OpenIDConnectTokenTableIDToken;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
import java.util.Set;
import lombok.NonNull;

public class OAuth2TokenUpdater {
   @NonNull
   private final TokenDataProvider tokenDataProvider;

   public void invalidate(OAuth2Token token) {
      AbstractTokenTableOAuth2Token abstractToken = AbstractTokenTableOAuth2Token.asTokenTableBasedOAuth2Token(token);
      abstractToken.setActive(false);
      this.updateToken(abstractToken);
   }

   public void increaseTokenUsage(OAuth2Token token) {
      AbstractTokenTableOAuth2Token abstractToken = AbstractTokenTableOAuth2Token.asTokenTableBasedOAuth2Token(token);
      abstractToken.increaseUsage();
      this.updateToken(abstractToken);
   }

   public void setGracePeriod(OAuth2RefreshToken refreshToken, Date gracePeriodEnd) {
      OAuth2TokenTableRefreshToken token = OAuth2TokenTableRefreshToken.asTokenTableBasedOAuth2RefreshToken(refreshToken);
      token.setGracePeriodEnd(gracePeriodEnd);
      token.setValidityRange(new DateRange(token.getValidityRange().getFromDate(), gracePeriodEnd));
      this.updateToken(token);
   }

   public void updateTokenScopes(OpenIDConnectIDToken idToken, Set<OAuth2Scope> scopes) {
      OpenIDConnectTokenTableIDToken token = OpenIDConnectTokenTableIDToken.asTokenTableBasedOpenIDConnectIDToken(idToken);
      token.setScope(scopes);
      this.updateToken(token);
   }

   private void updateToken(AbstractTokenTableOAuth2Token token) {
      try {
         this.tokenDataProvider.updateToken(token.getDelegate());
      } catch (PersisterException e) {
         throw new FailureException("Unable to update token: " + e.getMessage());
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   public OAuth2TokenUpdater(@NonNull TokenDataProvider tokenDataProvider) {
      if (tokenDataProvider == null) {
         throw new NullPointerException("tokenDataProvider is marked non-null but is null");
      }

      this.tokenDataProvider = tokenDataProvider;
   }
}
