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

import com.airlock.iam.common.api.domain.model.claims.ClaimValue;
import jakarta.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public final class ClaimSerializationUtils {
   private static final List<Class<?>> JSON_SERIALIZABLE_LEAF_CLASSES = List.of(Boolean.class, Number.class, String.class);

   public static Optional<ClaimValue> toJsonSerializable(@Nullable Object value) {
      return value == null ? Optional.of(() -> null) : Optional.of(value).filter(ClaimSerializationUtils::isJsonSerializableType).map(v -> () -> v);
   }

   public static boolean isJsonSerializableType(@Nullable Object value) {
      for (Class<?> jsonSerializableLeafClass : JSON_SERIALIZABLE_LEAF_CLASSES) {
         if (value == null || jsonSerializableLeafClass.isInstance(value)) {
            return true;
         }
      }

      return isNestedTypeSerializableList(value) || isNestedTypeSerializableMap(value);
   }

   private static boolean isNestedTypeSerializableList(Object value) {
      if (value instanceof Collection) {
         for (Object nestedValue : (Collection)value) {
            if (!isJsonSerializableType(nestedValue)) {
               return false;
            }
         }

         return true;
      } else {
         return false;
      }
   }

   private static boolean isNestedTypeSerializableMap(Object value) {
      if (value instanceof Map<?, ?> map) {
         for (Object key : map.keySet()) {
            if (!(key instanceof String)) {
               return false;
            }
         }

         for (Object nestedValue : map.values()) {
            if (!isJsonSerializableType(nestedValue)) {
               return false;
            }
         }

         return true;
      } else {
         return false;
      }
   }

   private ClaimSerializationUtils() {
      throw new AssertionError();
   }
}
