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

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;

public final class LinkedTokenReference {
   private static final Pattern TOKEN_PATTERN = Pattern.compile("[a-zA-Z0-9_-]+~[a-zA-Z0-9+/]+={0,2}");
   private final Optional<OAuth2TokenKey> tokenKey;
   private final String tokenHash;

   private LinkedTokenReference(String tokenHash) {
      this.tokenKey = Optional.empty();
      this.tokenHash = tokenHash;
   }

   private LinkedTokenReference(OAuth2TokenKey tokenKey, String tokenHash) {
      this.tokenKey = Optional.of(tokenKey);
      this.tokenHash = tokenHash;
   }

   public static LinkedTokenReference fromRawToken(RawOAuth2TokenWithHash rawToken) {
      return new LinkedTokenReference(rawToken.getTokenKey(), rawToken.getHash());
   }

   public static LinkedTokenReference fromDbValue(String value) {
      if (StringUtils.isBlank(value)) {
         throw new ViolationException("TokenReference Value is null or empty.");
      } else if (TOKEN_PATTERN.matcher(value).matches()) {
         String key = StringUtils.substringBefore(value, "~");
         String hash = StringUtils.substringAfter(value, "~");
         return new LinkedTokenReference(OAuth2TokenKey.tokenKey(key), hash);
      } else {
         return new LinkedTokenReference(value);
      }
   }

   public String toDbValue() {
      return this.tokenKey.isPresent() ? this.tokenKey.get().getValue() + "~" + this.tokenHash : this.tokenHash;
   }

   @SuppressFBWarnings(justification = "generated code")
   public Optional<OAuth2TokenKey> getTokenKey() {
      return this.tokenKey;
   }

   @SuppressFBWarnings(justification = "generated code")
   public String getTokenHash() {
      return this.tokenHash;
   }
}
