package com.airlock.iam.transactionapproval.domain.model.message;

import com.airlock.iam.base.misc.message.MessageFormattingException;
import com.airlock.iam.base.misc.message.MessageTemplate;
import com.airlock.iam.common.api.domain.model.user.CurrentLocale;
import com.airlock.iam.core.misc.impl.authen.StringResourceProvider;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MessageProviderStringResolver {
   private final Provider<StringResourceProvider> stringResourceProvider;
   private final Provider<CurrentLocale> currentLocale;
   private final Provider<MessageDataProvider> valueProvider;
   private static final Pattern GROWABLE_VARIABLE_PATTERN = Pattern.compile("\\$\\{([a-zA-Z][a-zA-Z0-9]*),");
   private static final Pattern TEMPLATE_VARIABLE_PATTERN = Pattern.compile("\\$\\{([a-zA-Z][a-zA-Z0-9]*)}");
   private static final String TOKEN_VARIABLE_EXTERN = "${TOKEN}";
   private static final String TOKEN_VARIABLE_INTERN = "$TOKEN$";

   @Inject
   public MessageProviderStringResolver(
      Provider<StringResourceProvider> stringResourceProviderProvider, Provider<CurrentLocale> locale, Provider<MessageDataProvider> valueProvider
   ) {
      this.stringResourceProvider = stringResourceProviderProvider;
      this.currentLocale = locale;
      this.valueProvider = valueProvider;
   }

   public MessageTemplate getMessageTemplateInGrowableFormat(String messageTranslationKey) {
      String finalTemplateKey = this.replaceNonGrowableVariables(messageTranslationKey);
      String messageTemplate = this.getStringResourceForKey(finalTemplateKey)
         .map(this::replaceToken)
         .orElseThrow(() -> new MessageFormattingException("No message template found for key '" + finalTemplateKey + "'."));
      String messageTemplateWithFixValues = this.replaceNonGrowableVariables(messageTemplate);
      Matcher matcher = GROWABLE_VARIABLE_PATTERN.matcher(messageTemplateWithFixValues);
      StringBuilder builder = new StringBuilder();
      ArrayList<Object> values = new ArrayList<>();
      int index = 0;
      MessageDataProvider data = (MessageDataProvider)this.valueProvider.get();

      while (matcher.find()) {
         String variable = matcher.group(1);
         values.add(data.getValueForKey(variable).orElseThrow(this.missingParameterValue(variable)));
         matcher.appendReplacement(builder, "{" + index + ",");
         index++;
      }

      matcher.appendTail(builder);
      return MessageTemplate.fromIndexedParameters(builder.toString(), values.toArray());
   }

   String replaceNonGrowableVariables(String key) {
      Matcher matcher = TEMPLATE_VARIABLE_PATTERN.matcher(key);
      MessageDataProvider data = (MessageDataProvider)this.valueProvider.get();
      StringBuilder stringBuilder = new StringBuilder();

      while (matcher.find()) {
         String variable = matcher.group(1);
         String value = data.getValueForKey(variable).map(String.class::cast).orElseThrow(this.missingParameterValue(variable));
         matcher.appendReplacement(stringBuilder, Matcher.quoteReplacement(value));
      }

      matcher.appendTail(stringBuilder);
      return stringBuilder.toString();
   }

   private String replaceToken(String template) {
      return template.replace("${TOKEN}", "$TOKEN$");
   }

   public Optional<String> getStringResourceForKey(String key) {
      return ((StringResourceProvider)this.stringResourceProvider.get()).translateResourceKey(((CurrentLocale)this.currentLocale.get()).get(), key);
   }

   private Supplier<MessageFormattingException> missingParameterValue(String variable) {
      return () -> new MessageFormattingException("Cannot find value for variable \"" + variable + "\"");
   }
}
