package com.airlock.iam.oauth2.domain.model.token;

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.core.misc.persistency.token.TokenBean;
import java.util.Date;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;

public class OAuth2TokenTableRefreshToken extends AbstractTokenTableOAuth2Token implements OAuth2RefreshToken {
   protected static final String REFRESH_TOKEN_SUBTYPE = "refresh_token";

   public static OAuth2TokenTableRefreshToken asTokenTableBasedOAuth2RefreshToken(OAuth2Token token) {
      if (token instanceof OAuth2TokenTableRefreshToken t) {
         return t;
      } else {
         throw new ViolationException("Cannot cast " + token.getClass().getSimpleName() + " to " + OAuth2TokenTableRefreshToken.class.getSimpleName());
      }
   }

   public OAuth2TokenTableRefreshToken(TokenBean delegate) {
      super(delegate);
   }

   public static OAuth2TokenTableRefreshToken createOAuth2RefreshToken(
      TokenBean delegate, RawOAuth2TokenWithHash rawRefreshToken, SessionInfo session, RefreshTokenInfo refreshTokenInfo, int expiresIn
   ) {
      OAuth2TokenTableRefreshToken token = new OAuth2TokenTableRefreshToken(delegate);
      token.initialize(OAuth2Token.OAuth2TokenType.REFRESH_TOKEN, rawRefreshToken.getTokenKey(), session, refreshTokenInfo.scopes(), expiresIn);
      token.setHashedTokenSecret(rawRefreshToken.getHash());
      token.setAccessTokenReference(refreshTokenInfo.accessTokenReference());
      return token;
   }

   @Override
   public String getHashedTokenSecret() {
      return this.getGenericDataElement2();
   }

   private void setHashedTokenSecret(String tokenSecretHash) {
      this.setGenericDataElement2(tokenSecretHash);
   }

   @Override
   public boolean hasAccessTokenReference() {
      return StringUtils.isNotBlank(this.getGenericDataElement5());
   }

   @Override
   public Optional<LinkedTokenReference> getAccessTokenReference() {
      String refreshTokenString = this.getGenericDataElement5();
      return StringUtils.isBlank(refreshTokenString) ? Optional.empty() : Optional.of(LinkedTokenReference.fromDbValue(refreshTokenString));
   }

   private void setAccessTokenReference(LinkedTokenReference accessToken) {
      this.setGenericDataElement5(accessToken.toDbValue());
   }

   public void setGracePeriodEnd(Date gracePeriodEnd) {
      if (StringUtils.isNotBlank(this.getDelegate().getGenericDataElement11())) {
         throw new IllegalStateException("Cannot set grace period. Grace period is already set!");
      }

      this.getDelegate().setGenericDataElement11(Long.toString(gracePeriodEnd.getTime()));
   }

   @Override
   public Optional<Date> getGracePeriodEnd() {
      return StringUtils.isBlank(this.getDelegate().getGenericDataElement11())
         ? Optional.empty()
         : Optional.of(new Date(Long.parseLong(this.getDelegate().getGenericDataElement11())));
   }

   @Override
   public boolean isGracePeriodExpired() {
      Optional<Date> gracePeriodEnd = this.getGracePeriodEnd();
      return gracePeriodEnd.isEmpty() ? false : gracePeriodEnd.get().before(new Date());
   }
}
