package com.airlock.iam.techclientreg.domain.model.registration;

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.techclient.api.domain.model.oauth2.OAuth2TechnicalClientMetadataBuilder;
import com.airlock.iam.techclientreg.api.domain.model.oauth2.OAuth2ClientRegistrationError;
import com.airlock.iam.techclientreg.api.domain.model.oauth2.OAuth2ClientRegistrationRequest;
import com.airlock.iam.techclientreg.api.domain.service.oauth2.OAuth2ClientMetadataProcessor;
import com.airlock.iam.techclientreg.application.configuration.registration.ClientNameProcessorConfig;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Map.Entry;
import java.util.stream.Collectors;

@LogicForConfig(ClientNameProcessorConfig.class)
public class ClientNameProcessor implements OAuth2ClientMetadataProcessor {
   private static final ELogger LOG = ELoggerFactory.getLogger(ClientNameProcessor.class);
   private final Provider<ClientNameProcessorConfig> config;
   private final ClientMetadataAttributeValidator validator;

   @Inject
   public ClientNameProcessor(Provider<ClientNameProcessorConfig> config, ClientMetadataAttributeValidator validator) {
      this.config = config;
      this.validator = validator;
   }

   @Override
   public Optional<OAuth2ClientRegistrationError> updateClient(OAuth2ClientRegistrationRequest request, OAuth2TechnicalClientMetadataBuilder clientBuilder) {
      Optional<String> verifiedName = this.extractAndVerifyClientName(request);
      if (verifiedName.isEmpty() && ((ClientNameProcessorConfig)this.config.get()).isMandatory()) {
         return Optional.of(OAuth2ClientRegistrationError.invalidClientMetadata("client_name missing or invalid"));
      }

      clientBuilder.clientName(verifiedName);
      this.collectValidTranslations(request).forEach((locale, translation) -> {
         LOG.debug("Using client_name translation for " + LogUtil.logSafeQuote(locale) + " received from the client: " + LogUtil.logSafeString(translation));
         clientBuilder.clientNameTranslation(locale, translation);
      });
      return Optional.empty();
   }

   private Optional<String> extractAndVerifyClientName(OAuth2ClientRegistrationRequest request) {
      Optional<String> requestedName = request.getMetadata().clientName();
      if (requestedName.isEmpty()) {
         return Optional.empty();
      }

      if (!this.isValidName(requestedName.get())) {
         return Optional.empty();
      }

      LOG.debug("Using client_name value received from the client: " + LogUtil.logSafeString(requestedName.get()));
      return requestedName;
   }

   private Map<Locale, String> collectValidTranslations(OAuth2ClientRegistrationRequest request) {
      return request.getMetadata()
         .clientNameTranslations()
         .entrySet()
         .stream()
         .filter(e -> this.isValidName(e.getValue()))
         .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
   }

   private boolean isValidName(String name) {
      return this.validator.isValidMetadataAttribute("client_name", name, 200, ((ClientNameProcessorConfig)this.config.get()).getAllowedValues());
   }
}
