package com.airlock.iam.authentication.domain.model.idpropagation;

import com.airlock.iam.authentication.application.configuration.idpropagation.ContextDataUsernameProviderConfig;
import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.common.api.domain.model.contextdata.ContextDataItem;
import com.airlock.iam.common.api.domain.model.user.User;
import com.airlock.iam.common.api.domain.model.user.UserIdentity;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Objects;
import java.util.Optional;

@LogicForConfig(ContextDataUsernameProviderConfig.class)
public class ContextDataUsernameProvider implements UsernameProvider {
   private final ContextDataUsernameProviderConfig config;
   private final Provider<User> user;

   @Inject
   public ContextDataUsernameProvider(ContextDataUsernameProviderConfig config, Provider<User> user) {
      this.config = config;
      this.user = user;
   }

   @Override
   public Optional<String> provideUsername(UserIdentity userId) {
      if (!userId.id().hasValue(this.user().getName())) {
         throw new FailureException("Expected principal for user ID " + userId + " but found " + this.user().getName());
      } else {
         Optional<String> data = this.contextDataValue();
         if (data.isPresent()) {
            return data;
         } else if (this.config.isMandatory()) {
            throw new FailureException("Required context-data field '" + this.config.getPropertyName() + "' is empty");
         } else {
            return Optional.empty();
         }
      }
   }

   private Optional<String> contextDataValue() {
      return this.user().getContextData().find(this.config.getPropertyName()).map(ContextDataItem::getValue).map(Objects::toString);
   }

   private User user() {
      return (User)this.user.get();
   }
}
