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

import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.exception.PropertyTypeMismatchException;
import com.airlock.iam.plugin.api.valuereader.StringListPropertyValueReader;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import com.nimbusds.jwt.JWTClaimsSet;
import java.util.List;
import java.util.Optional;

public final class JwtTicketEncoderDecoderSettingsValidator {
   private JwtTicketEncoderDecoderSettingsValidator() {
   }

   public static void ensureListDoesNotContainRegisteredClaims(
      PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, String claimsPropertyName
   ) throws PropertyTypeMismatchException, PropertyConstraintViolationException {
      Optional<String> validationError = Optional.of(StringListPropertyValueReader.effectiveStringListConfigValue(pc, claimsPropertyName, env, context))
         .flatMap(JwtTicketEncoderDecoderSettingsValidator::ensureClaimsContainsNoRegisteredClaims);
      if (validationError.isPresent()) {
         throw new PropertyConstraintViolationException(claimsPropertyName, pc, env, context, validationError.get());
      }
   }

   private static Optional<String> ensureClaimsContainsNoRegisteredClaims(List<String> claimsToTest) {
      List<String> registeredClaimsStoredAsArray = claimsToTest.stream().filter(JWTClaimsSet.getRegisteredNames()::contains).toList();
      return !registeredClaimsStoredAsArray.isEmpty()
         ? Optional.of("Registered claim names (" + registeredClaimsStoredAsArray + ") are not allowed. They are propagated as specified in the RFC.")
         : Optional.empty();
   }

   public static void ensureNoClaimsAreConfiguredAsBothArrayAndJsonClaims(
      PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, String arrayClaimsPropertyName, String jsonClaimsPropertyName
   ) throws PropertyTypeMismatchException, PropertyConstraintViolationException {
      List<String> arrayClaims = StringListPropertyValueReader.effectiveStringListConfigValue(pc, arrayClaimsPropertyName, env, context);
      List<String> jsonClaims = StringListPropertyValueReader.effectiveStringListConfigValue(pc, jsonClaimsPropertyName, env, context);
      Optional<String> validationError = ensureThatClaimsHaveNoIntersection(arrayClaims, jsonClaims);
      if (validationError.isPresent()) {
         throw new PropertyConstraintViolationException(arrayClaimsPropertyName, pc, env, context, validationError.get());
      }
   }

   private static Optional<String> ensureThatClaimsHaveNoIntersection(List<String> claimList1, List<String> claimList2) {
      SetView<String> intersection = Sets.intersection(Sets.newHashSet(claimList1), Sets.newHashSet(claimList2));
      return !intersection.isEmpty()
         ? Optional.of("Intersecting claim names (" + intersection + ") are not allowed in claims stored as array and claims stored as JSON.")
         : Optional.empty();
   }
}
