package com.airlock.iam.flow.shared.domain.model.valueprovider;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.misc.message.ParameterizedString;
import com.airlock.iam.common.api.domain.model.valueprovider.ValueProvider;
import com.airlock.iam.core.misc.impl.authen.StringResourceProvider;
import com.airlock.iam.core.misc.util.LanguageUtils;
import com.airlock.iam.flow.shared.api.domain.model.valueprovider.ValueMapProvider;
import com.airlock.iam.flow.shared.application.configuration.valueprovider.TranslationValueProviderConfig;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nonnull;
import jakarta.inject.Inject;
import java.util.Locale;
import java.util.Map;
import lombok.NonNull;

@LogicForConfig(TranslationValueProviderConfig.class)
public class TranslationValueProvider implements ValueProvider<String> {
   @NonNull
   private final ParameterizedString parameterizedTranslationKey;
   @NonNull
   private final StringResourceProvider stringResourceProvider;
   @NonNull
   private final ValueMapProvider valueMapProvider;
   @NonNull
   private final ValueProvider<String> localeProvider;

   @Inject
   public TranslationValueProvider(
      @NonNull ParameterizedString parameterizedTranslationKey,
      @Nonnull StringResourceProvider stringResourceProvider,
      @Nonnull ValueMapProvider valueMapProvider,
      @Nonnull ValueProvider<String> localeProvider
   ) {
      if (parameterizedTranslationKey == null) {
         throw new NullPointerException("parameterizedTranslationKey is marked non-null but is null");
      }

      this.parameterizedTranslationKey = parameterizedTranslationKey;
      this.valueMapProvider = valueMapProvider;
      this.stringResourceProvider = stringResourceProvider;
      this.localeProvider = localeProvider;
   }

   public String getValue() {
      Map<String, Object> values = this.valueMapProvider.provideValueMap();
      String formattedTranslationKey = this.parameterizedTranslationKey.replaceParameters(values);
      Locale locale = LanguageUtils.getLocale(this.localeProvider.getValue());
      return ParameterizedString.parameterizedString(
            this.stringResourceProvider
               .translateResourceKey(locale, formattedTranslationKey)
               .orElseThrow(() -> new FailureException(String.format("No translation found for key '%s'", formattedTranslationKey)))
         )
         .replaceParameters(values);
   }

   @SuppressFBWarnings(justification = "generated code")
   public static TranslationValueProvider.TranslationValueProviderBuilder builder() {
      return new TranslationValueProvider.TranslationValueProviderBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class TranslationValueProviderBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private ParameterizedString parameterizedTranslationKey;
      @SuppressFBWarnings(justification = "generated code")
      private StringResourceProvider stringResourceProvider;
      @SuppressFBWarnings(justification = "generated code")
      private ValueMapProvider valueMapProvider;
      @SuppressFBWarnings(justification = "generated code")
      private ValueProvider<String> localeProvider;

      @SuppressFBWarnings(justification = "generated code")
      TranslationValueProviderBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public TranslationValueProvider.TranslationValueProviderBuilder parameterizedTranslationKey(@NonNull ParameterizedString parameterizedTranslationKey) {
         if (parameterizedTranslationKey == null) {
            throw new NullPointerException("parameterizedTranslationKey is marked non-null but is null");
         }

         this.parameterizedTranslationKey = parameterizedTranslationKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TranslationValueProvider.TranslationValueProviderBuilder stringResourceProvider(@NonNull StringResourceProvider stringResourceProvider) {
         if (stringResourceProvider == null) {
            throw new NullPointerException("stringResourceProvider is marked non-null but is null");
         }

         this.stringResourceProvider = stringResourceProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TranslationValueProvider.TranslationValueProviderBuilder valueMapProvider(@NonNull ValueMapProvider valueMapProvider) {
         if (valueMapProvider == null) {
            throw new NullPointerException("valueMapProvider is marked non-null but is null");
         }

         this.valueMapProvider = valueMapProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TranslationValueProvider.TranslationValueProviderBuilder localeProvider(@NonNull ValueProvider<String> localeProvider) {
         if (localeProvider == null) {
            throw new NullPointerException("localeProvider is marked non-null but is null");
         }

         this.localeProvider = localeProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TranslationValueProvider build() {
         return new TranslationValueProvider(this.parameterizedTranslationKey, this.stringResourceProvider, this.valueMapProvider, this.localeProvider);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "TranslationValueProvider.TranslationValueProviderBuilder(parameterizedTranslationKey="
            + this.parameterizedTranslationKey
            + ", stringResourceProvider="
            + this.stringResourceProvider
            + ", valueMapProvider="
            + this.valueMapProvider
            + ", localeProvider="
            + this.localeProvider
            + ")";
      }
   }
}
