package com.airlock.iam.saml2.domain.model.assertion.attribute;

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.api.domain.model.contextdata.ContextDataItem;
import com.airlock.iam.common.api.domain.model.user.User;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.saml2.application.configuration.assertion.attribute.ContextDataAttributeConfig;
import com.airlock.iam.saml2.domain.model.assertion.FlowSaml2Attribute;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

@LogicForConfig(ContextDataAttributeConfig.class)
public class Saml2ContextDataAttributeImpl implements Saml2AttributeProvider {
   private static final ELogger LOG = ELoggerFactory.getLogger(Saml2ContextDataAttributeImpl.class);
   private final ContextDataAttributeConfig config;
   private final Provider<User> userProvider;

   @Inject
   public Saml2ContextDataAttributeImpl(ContextDataAttributeConfig config, Provider<User> userProvider) {
      this.config = config;
      this.userProvider = userProvider;
   }

   @Override
   public Optional<FlowSaml2Attribute> getAttribute() {
      Optional<ContextDataItem<Object>> value = ((User)this.userProvider.get()).getContextData().find(this.config.getContextDataName());
      if (value.isEmpty()) {
         return Optional.empty();
      }

      List<String> valueList = getValueList(value.get().getValue(), this.config.getContextDataName());
      return valueList.isEmpty()
         ? Optional.empty()
         : Optional.of(new FlowSaml2Attribute(this.config.getSamlAttributeName(), valueList, this.config.getNameFormat()));
   }

   public static List<String> getValueList(Object contextDataValue, String contextDataName) {
      if (contextDataValue instanceof Collection) {
         return filterEmptyValues(((Collection)contextDataValue).stream());
      }

      if (contextDataValue instanceof String[]) {
         return filterEmptyValues(Stream.of((String[])contextDataValue));
      }

      if (contextDataValue != null) {
         return List.of(contextDataValue.toString());
      }

      LOG.info("No value found in context data for key " + LogUtil.quote(contextDataName) + ", ignoring SAML attribute.");
      return List.of();
   }

   private static List<String> filterEmptyValues(Stream<?> stream) {
      return stream.filter(Objects::nonNull).map(Object::toString).filter(Objects::nonNull).toList();
   }
}
