package com.airlock.iam.common.domain.model.sso;

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.common.application.configuration.sso.DefaultSsoTicketContextDataExtractorConfig;
import com.airlock.iam.common.domain.service.sso.ContextDataEntry;
import com.airlock.iam.core.misc.sso.KeyEntry;
import com.airlock.iam.core.misc.util.ticket.KeyMultiValue;
import com.airlock.iam.core.misc.util.ticket.Ticket;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@LogicForConfig(DefaultSsoTicketContextDataExtractorConfig.class)
public final class DefaultSsoTicketContextDataExtractorImpl implements SsoTicketContextDataExtractor {
   private final Provider<DefaultSsoTicketContextDataExtractorConfig> config;

   @Inject
   public DefaultSsoTicketContextDataExtractorImpl(Provider<DefaultSsoTicketContextDataExtractorConfig> config) {
      this.config = config;
   }

   @Override
   public Set<ContextDataEntry> extract(Ticket ticket) {
      return this.extractContextDataFromTicket(ticket);
   }

   private Set<ContextDataEntry> extractContextDataFromTicket(Ticket ticket) {
      return ((DefaultSsoTicketContextDataExtractorConfig)this.config.get())
         .getTicketKeys()
         .stream()
         .map(keyEntry -> this.extractContextData(ticket, keyEntry))
         .filter(Optional::isPresent)
         .map(Optional::get)
         .collect(Collectors.toCollection(LinkedHashSet::new));
   }

   private Optional<ContextDataEntry> extractContextData(Ticket ticket, KeyEntry keyEntry) {
      KeyMultiValue kmv = ticket.getValueForName(keyEntry.getTicketKey());
      if (kmv == null) {
         return Optional.empty();
      }

      if (keyEntry.getStoreFirstValueOnly()) {
         return Optional.ofNullable(kmv.getFirstValue()).map(value -> ContextDataEntry.contextData(contextDataKey(keyEntry), value));
      }

      String[] values = kmv.getValues();
      return Optional.of(ContextDataEntry.contextData(contextDataKey(keyEntry), values == null ? Collections.emptyList() : Arrays.asList(values)));
   }

   private static String contextDataKey(KeyEntry keyEntry) {
      return Optional.ofNullable(keyEntry.getContextDataKey()).orElseGet(keyEntry::getTicketKey);
   }
}
