package com.airlock.iam.common.domain.model.valueprovider.contextdata;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
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.valueprovider.ValueProvider;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;
import lombok.NonNull;

public final class GenericContextDataValueProvider<T> implements ValueProvider<T> {
   @NonNull
   private final String contextDataName;
   @NonNull
   private final User user;
   private final boolean valueMandatory;

   @Override
   public T getValue() {
      Optional<ContextDataItem<T>> contextDataItem = this.user.getContextData().find(this.contextDataName);
      Optional<T> contextDataItemValue = contextDataItem.map(ContextDataItem::getValue);
      if (this.valueMandatory && contextDataItemValue.isEmpty()) {
         throw new FailureException(
            String.format("The configured context data item (%s) is mandatory but no value exists for the current user", this.contextDataName)
         );
      } else {
         return contextDataItemValue.orElse(null);
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   GenericContextDataValueProvider(@NonNull String contextDataName, @NonNull User user, boolean valueMandatory) {
      if (contextDataName == null) {
         throw new NullPointerException("contextDataName is marked non-null but is null");
      }

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

      this.contextDataName = contextDataName;
      this.user = user;
      this.valueMandatory = valueMandatory;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static <T> GenericContextDataValueProvider.GenericContextDataValueProviderBuilder<T> builder() {
      return new GenericContextDataValueProvider.GenericContextDataValueProviderBuilder<>();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class GenericContextDataValueProviderBuilder<T> {
      @SuppressFBWarnings(justification = "generated code")
      private String contextDataName;
      @SuppressFBWarnings(justification = "generated code")
      private User user;
      @SuppressFBWarnings(justification = "generated code")
      private boolean valueMandatory;

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

      @SuppressFBWarnings(justification = "generated code")
      public GenericContextDataValueProvider.GenericContextDataValueProviderBuilder<T> contextDataName(@NonNull String contextDataName) {
         if (contextDataName == null) {
            throw new NullPointerException("contextDataName is marked non-null but is null");
         }

         this.contextDataName = contextDataName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericContextDataValueProvider.GenericContextDataValueProviderBuilder<T> user(@NonNull User user) {
         if (user == null) {
            throw new NullPointerException("user is marked non-null but is null");
         }

         this.user = user;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericContextDataValueProvider.GenericContextDataValueProviderBuilder<T> valueMandatory(boolean valueMandatory) {
         this.valueMandatory = valueMandatory;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericContextDataValueProvider<T> build() {
         return new GenericContextDataValueProvider<>(this.contextDataName, this.user, this.valueMandatory);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "GenericContextDataValueProvider.GenericContextDataValueProviderBuilder(contextDataName="
            + this.contextDataName
            + ", user="
            + this.user
            + ", valueMandatory="
            + this.valueMandatory
            + ")";
      }
   }
}
