package com.airlock.iam.saml2.domain.model.sp;

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.base.misc.log.LogUtil;
import com.google.common.annotations.VisibleForTesting;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.Validate;

public final class Saml2Attributes {
   private final Map<String, List<String>> attributes;

   public Saml2Attributes(Map<String, List<String>> attributes) {
      this.attributes = immutableCopy(attributes);
   }

   public static Saml2Attributes empty() {
      return new Saml2Attributes(Collections.emptyMap());
   }

   public Optional<String> getSingleValueAttribute(String name) {
      return Optional.ofNullable(this.attributes.get(name))
         .map(
            values -> {
               if (values.size() > 1) {
                  throw new ViolationException(
                     "SAML2 Attribute " + LogUtil.quote(name) + " was expected to be single-valued but contained " + values.size() + " values."
                  );
               } else {
                  return values.getFirst();
               }
            }
         );
   }

   public Optional<List<String>> getMultiValueAttribute(String name) {
      return Optional.ofNullable(this.attributes.get(name)).map(List::copyOf);
   }

   private static Map<String, List<String>> immutableCopy(Map<String, List<String>> attributes) {
      Map<String, List<String>> mutableMap = new HashMap<>();
      attributes.forEach((key, mutableList) -> {
         Validate.notEmpty(mutableList);
         mutableMap.put(key, List.copyOf((Collection<? extends String>)mutableList));
      });
      return Map.copyOf(mutableMap);
   }

   @VisibleForTesting
   public Map<String, List<String>> getMap() {
      return immutableCopy(this.attributes);
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public boolean equals(Object o) {
      if (o == this) {
         return true;
      } else if (!(o instanceof Saml2Attributes other)) {
         return false;
      } else {
         Object this$attributes = this.attributes;
         Object other$attributes = other.attributes;
         return this$attributes == null ? other$attributes == null : this$attributes.equals(other$attributes);
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public int hashCode() {
      int PRIME = 59;
      int result = 1;
      Object $attributes = this.attributes;
      return result * 59 + ($attributes == null ? 43 : $attributes.hashCode());
   }
}
