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

import com.airlock.iam.common.domain.model.principal.UserPrincipal;
import com.airlock.iam.transactionapproval.domain.model.flow.TransactionApprovalMessageAttributes;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;
import org.apache.commons.lang3.Strings;

public class MessageDataProvider {
   private static final String NOW_VARIABLE = "Now";
   private final Provider<UserPrincipal> userPrincipal;
   private final Provider<Optional<TransactionApprovalMessageAttributes>> messageAttributes;
   private final Provider<MessageValueEncoder> valueEncoder;

   @Inject
   public MessageDataProvider(
      Provider<UserPrincipal> userPrincipal,
      Provider<Optional<TransactionApprovalMessageAttributes>> messageAttributes,
      Provider<MessageValueEncoder> valueEncoder
   ) {
      this.userPrincipal = userPrincipal;
      this.messageAttributes = messageAttributes;
      this.valueEncoder = valueEncoder;
   }

   public Optional<Object> getValueForKey(String key) {
      Objects.requireNonNull(key);
      Optional<Object> candidate = this.findValueInMessageAttributes(key);
      if (candidate.isPresent()) {
         return candidate.map(this::encode);
      }

      candidate = this.findValueInContextData(key);
      return candidate.isPresent() ? candidate.map(this::encode) : this.tryResolveNow(key);
   }

   private Object encode(Object value) {
      return value instanceof String ? ((MessageValueEncoder)this.valueEncoder.get()).encode((String)value) : value;
   }

   private Optional<Object> findValueInMessageAttributes(String key) {
      return !((Optional)this.messageAttributes.get()).isPresent()
         ? Optional.empty()
         : Optional.ofNullable(((TransactionApprovalMessageAttributes)((Optional)this.messageAttributes.get()).get()).getAttributes().get(key));
   }

   private Optional<Object> findValueInContextData(String key) {
      return Optional.ofNullable(((UserPrincipal)this.userPrincipal.get()).user().getContextDataValue(key));
   }

   private Optional<Object> tryResolveNow(String key) {
      return Strings.CS.equals(key, "Now") ? Optional.of(new Date()) : Optional.empty();
   }
}
