package com.airlock.iam.common.infrastructure.event;

import com.airlock.iam.base.api.domain.model.event.DomainEvent;
import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.infrastructure.event.DomainEventValuesProvider;
import com.airlock.iam.common.api.domain.model.event.UserEvent;
import com.airlock.iam.common.domain.model.encoder.ValueMapEncoder;
import com.airlock.iam.common.domain.model.locale.ResourceKey;
import com.airlock.iam.common.domain.service.event.DomainEventMessageProvider;
import com.airlock.iam.common.domain.service.event.LocaleProvider;
import com.airlock.iam.core.misc.impl.authen.StringResourceProvider;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Locale;
import java.util.Map;
import lombok.NonNull;

public final class DomainEventMessageProviderImpl implements DomainEventMessageProvider {
   private final Provider<DomainEventValuesProvider> valueMapProvider;
   private final Provider<ValueMapEncoder> valueMapEncoder;
   private final Provider<LocaleProvider> localeProvider;
   private final Provider<StringResourceProvider> stringResourceProvider;

   @Inject
   DomainEventMessageProviderImpl(
      @NonNull Provider<DomainEventValuesProvider> valueMapProvider,
      @NonNull Provider<ValueMapEncoder> valueMapEncoder,
      @NonNull Provider<LocaleProvider> localeProvider,
      @NonNull Provider<StringResourceProvider> stringResourceProvider
   ) {
      if (valueMapProvider == null) {
         throw new NullPointerException("valueMapProvider is marked non-null but is null");
      }

      if (valueMapEncoder == null) {
         throw new NullPointerException("valueMapEncoder is marked non-null but is null");
      }

      if (localeProvider == null) {
         throw new NullPointerException("localeProvider is marked non-null but is null");
      }

      if (stringResourceProvider == null) {
         throw new NullPointerException("stringResourceProvider is marked non-null but is null");
      }

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

   @Override
   public String translate(DomainEvent event, ResourceKey resourceKey) {
      return ((StringResourceProvider)this.stringResourceProvider.get())
         .translateResourceKey(this.userLocale(event), resourceKey.getValue(), this.createValues(event))
         .orElseThrow(() -> new FailureException("Cannot translate template key: " + resourceKey.getValue()));
   }

   private Map<String, Object> createValues(DomainEvent event) {
      return ((ValueMapEncoder)this.valueMapEncoder.get())
         .encodeValues(((DomainEventValuesProvider)this.valueMapProvider.get()).provideValueMapForEvent(event));
   }

   private Locale userLocale(DomainEvent event) {
      return event instanceof UserEvent userEvent
         ? ((LocaleProvider)this.localeProvider.get()).userLocale(userEvent.userId())
         : ((LocaleProvider)this.localeProvider.get()).defaultLocale();
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class DomainEventMessageProviderImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Provider<DomainEventValuesProvider> valueMapProvider;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<ValueMapEncoder> valueMapEncoder;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<LocaleProvider> localeProvider;
      @SuppressFBWarnings(justification = "generated code")
      private Provider<StringResourceProvider> stringResourceProvider;

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

      @SuppressFBWarnings(justification = "generated code")
      public DomainEventMessageProviderImpl.DomainEventMessageProviderImplBuilder valueMapProvider(
         @NonNull Provider<DomainEventValuesProvider> 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 DomainEventMessageProviderImpl.DomainEventMessageProviderImplBuilder valueMapEncoder(@NonNull Provider<ValueMapEncoder> valueMapEncoder) {
         if (valueMapEncoder == null) {
            throw new NullPointerException("valueMapEncoder is marked non-null but is null");
         }

         this.valueMapEncoder = valueMapEncoder;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public DomainEventMessageProviderImpl.DomainEventMessageProviderImplBuilder localeProvider(@NonNull Provider<LocaleProvider> 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 DomainEventMessageProviderImpl.DomainEventMessageProviderImplBuilder stringResourceProvider(
         @NonNull Provider<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 DomainEventMessageProviderImpl build() {
         return new DomainEventMessageProviderImpl(this.valueMapProvider, this.valueMapEncoder, this.localeProvider, this.stringResourceProvider);
      }

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