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

import com.airlock.iam.common.api.domain.model.claims.ClaimsValidationResult;
import com.airlock.iam.common.api.domain.model.claims.ClaimsValidator;
import com.airlock.iam.common.api.domain.model.claims.InvalidClaim;
import com.airlock.iam.common.domain.model.claims.ClaimsValidationResultImpl;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;

public final class ClaimValidatorImpl implements ClaimsValidator {
   private final String claim;
   private final boolean mandatory;
   private final Pattern validationPattern;

   @Override
   public ClaimsValidationResult validate(Map<String, Object> claims) {
      Object claimValue = claims.get(this.claim);
      if (claimValue == null) {
         return this.mandatory ? this.claimInvalidResult("Claim declared mandatory but is missing") : ClaimsValidationResultImpl.claimsValidResult();
      } else {
         return Optional.ofNullable(this.validationPattern)
            .map(pattern -> this.claimMatches(claimValue.toString(), pattern))
            .orElse(ClaimsValidationResultImpl.claimsValidResult());
      }
   }

   private ClaimsValidationResult claimInvalidResult(String reason) {
      return ClaimsValidationResultImpl.claimsInvalidResult(Set.of(InvalidClaim.invalidClaim(this.claim, reason)));
   }

   private ClaimsValidationResult claimMatches(String claimValue, Pattern pattern) {
      return claimValue.matches(pattern.pattern())
         ? ClaimsValidationResultImpl.claimsValidResult()
         : this.claimInvalidResult("Claim does not match the defined validation pattern: " + this.validationPattern);
   }

   @SuppressFBWarnings(justification = "generated code")
   ClaimValidatorImpl(String claim, boolean mandatory, Pattern validationPattern) {
      this.claim = claim;
      this.mandatory = mandatory;
      this.validationPattern = validationPattern;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static ClaimValidatorImpl.ClaimValidatorImplBuilder builder() {
      return new ClaimValidatorImpl.ClaimValidatorImplBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class ClaimValidatorImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String claim;
      @SuppressFBWarnings(justification = "generated code")
      private boolean mandatory;
      @SuppressFBWarnings(justification = "generated code")
      private Pattern validationPattern;

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

      @SuppressFBWarnings(justification = "generated code")
      public ClaimValidatorImpl.ClaimValidatorImplBuilder claim(String claim) {
         this.claim = claim;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ClaimValidatorImpl.ClaimValidatorImplBuilder mandatory(boolean mandatory) {
         this.mandatory = mandatory;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ClaimValidatorImpl.ClaimValidatorImplBuilder validationPattern(Pattern validationPattern) {
         this.validationPattern = validationPattern;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ClaimValidatorImpl build() {
         return new ClaimValidatorImpl(this.claim, this.mandatory, this.validationPattern);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "ClaimValidatorImpl.ClaimValidatorImplBuilder(claim="
            + this.claim
            + ", mandatory="
            + this.mandatory
            + ", validationPattern="
            + this.validationPattern
            + ")";
      }
   }
}
