package com.airlock.iam.common.domain.service.jwt;

import com.airlock.iam.base.misc.time.RealTimeProvider;
import com.airlock.iam.base.misc.time.TimeProvider;
import com.airlock.iam.common.domain.model.jwt.JwtKeys;
import com.airlock.iam.common.domain.service.jwt.encryption.JwtTicketDirectAesEncrypterDecrypter;
import com.airlock.iam.common.domain.service.jwt.encryption.JwtTicketEncrypter;
import com.airlock.iam.common.domain.service.jwt.signature.HmacJwtSigner;
import com.airlock.iam.common.domain.service.jwt.signature.JwtSigner;
import com.airlock.iam.core.misc.util.ticket.Ticket;
import com.airlock.iam.core.misc.util.ticket.TicketEncodingException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public final class EncryptingJwtTicketEncoderImpl implements EncryptingJwtTicketEncoder {
   private final JwtTicketEncoderImpl encoder;

   public EncryptingJwtTicketEncoderImpl(
      Optional<String> usernameTicketKey,
      Optional<String> issuer,
      List<String> audience,
      Integer validNotBeforeSkew,
      List<String> claimsStoredAsArray,
      JwtSigner signer,
      JwtTicketEncrypter encrypter,
      TimeProvider timeProvider,
      boolean useTicketExpiryDate
   ) {
      this.encoder = JwtTicketEncoderImpl.builder(signer, timeProvider)
         .usernameTicketKey(usernameTicketKey)
         .validNotBeforeSkew(validNotBeforeSkew)
         .issuer(issuer)
         .audience(audience)
         .claimsStoredAsArray(claimsStoredAsArray)
         .encrypter(Optional.of(encrypter))
         .useTicketExpiryDate(useTicketExpiryDate)
         .build();
   }

   public static EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder builder(JwtKeys jwtKeys) {
      return new EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder()
         .usernameTicketKey(Optional.of("username"))
         .signer(HmacJwtSigner.builder().hmacAlgorithm(DefaultSecureJwtConfig.DEFAULT_HMAC_ALGORITHM).base64EncodedHmacKey(jwtKeys.hmacKey()).build())
         .encrypter(JwtTicketDirectAesEncrypterDecrypter.createDefaultEncryptorDecryptor(jwtKeys.encryptionKey()))
         .timeProvider(new RealTimeProvider())
         .validNotBeforeSkew(5)
         .issuer(Optional.empty())
         .audience(Collections.emptyList())
         .useTicketExpiryDate(true)
         .claimsStoredAsArray(Collections.emptyList());
   }

   @Override
   public String encode(Ticket ticket, String urlEncodingScheme) throws TicketEncodingException {
      return this.encoder.encode(ticket, urlEncodingScheme);
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class EncryptingJwtTicketEncoderImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Optional<String> usernameTicketKey;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<String> issuer;
      @SuppressFBWarnings(justification = "generated code")
      private List<String> audience;
      @SuppressFBWarnings(justification = "generated code")
      private Integer validNotBeforeSkew;
      @SuppressFBWarnings(justification = "generated code")
      private List<String> claimsStoredAsArray;
      @SuppressFBWarnings(justification = "generated code")
      private JwtSigner signer;
      @SuppressFBWarnings(justification = "generated code")
      private JwtTicketEncrypter encrypter;
      @SuppressFBWarnings(justification = "generated code")
      private TimeProvider timeProvider;
      @SuppressFBWarnings(justification = "generated code")
      private boolean useTicketExpiryDate;

      @SuppressFBWarnings(justification = "generated code")
      EncryptingJwtTicketEncoderImplBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder usernameTicketKey(Optional<String> usernameTicketKey) {
         this.usernameTicketKey = usernameTicketKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder issuer(Optional<String> issuer) {
         this.issuer = issuer;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder audience(List<String> audience) {
         this.audience = audience;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder validNotBeforeSkew(Integer validNotBeforeSkew) {
         this.validNotBeforeSkew = validNotBeforeSkew;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder claimsStoredAsArray(List<String> claimsStoredAsArray) {
         this.claimsStoredAsArray = claimsStoredAsArray;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder signer(JwtSigner signer) {
         this.signer = signer;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder encrypter(JwtTicketEncrypter encrypter) {
         this.encrypter = encrypter;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder timeProvider(TimeProvider timeProvider) {
         this.timeProvider = timeProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder useTicketExpiryDate(boolean useTicketExpiryDate) {
         this.useTicketExpiryDate = useTicketExpiryDate;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public EncryptingJwtTicketEncoderImpl build() {
         return new EncryptingJwtTicketEncoderImpl(
            this.usernameTicketKey,
            this.issuer,
            this.audience,
            this.validNotBeforeSkew,
            this.claimsStoredAsArray,
            this.signer,
            this.encrypter,
            this.timeProvider,
            this.useTicketExpiryDate
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "EncryptingJwtTicketEncoderImpl.EncryptingJwtTicketEncoderImplBuilder(usernameTicketKey="
            + this.usernameTicketKey
            + ", issuer="
            + this.issuer
            + ", audience="
            + this.audience
            + ", validNotBeforeSkew="
            + this.validNotBeforeSkew
            + ", claimsStoredAsArray="
            + this.claimsStoredAsArray
            + ", signer="
            + this.signer
            + ", encrypter="
            + this.encrypter
            + ", timeProvider="
            + this.timeProvider
            + ", useTicketExpiryDate="
            + this.useTicketExpiryDate
            + ")";
      }
   }
}
