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

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.common.api.domain.model.phonenumber.PhoneNumber;
import com.airlock.iam.flow.shared.api.domain.model.valueprovider.ValueMapProvider;
import com.airlock.iam.flow.shared.api.domain.service.FlowAttributeService;
import com.airlock.iam.flow.shared.application.configuration.valueprovider.MtanTokenFlowValueMapProviderConfig;
import com.airlock.iam.flow.shared.domain.model.mtan.MtanTokenChangeDescription;
import com.airlock.iam.flow.shared.domain.model.mtan.MtanTokenDeletionDescription;
import com.airlock.iam.flow.shared.domain.model.mtan.SelectedMtanToken;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@LogicForConfig(MtanTokenFlowValueMapProviderConfig.class)
public final class MtanTokenFlowValueMapProvider implements ValueMapProvider {
   private final Provider<FlowAttributeService> attributes;

   @Inject
   MtanTokenFlowValueMapProvider(Provider<FlowAttributeService> attributes) {
      this.attributes = attributes;
   }

   @Override
   public Map<String, Object> provideValueMap() {
      Map<String, Object> map = new HashMap<>();
      this.addSelectedMtanTokenValues(map);
      this.addChangedMtanTokenValues(map);
      this.addDeletedMtanTokenValues(map);
      return Map.copyOf(map);
   }

   private void addChangedMtanTokenValues(Map<String, Object> map) {
      Optional<MtanTokenChangeDescription> change = ((FlowAttributeService)this.attributes.get()).findAttribute(MtanTokenChangeDescription.class);
      Optional<String> existingPhoneNumber = change.flatMap(MtanTokenChangeDescription::getExistingToken)
         .map(SelectedMtanToken::getPhoneNumber)
         .map(PhoneNumber::getValue);
      Optional<String> existingLabel = change.flatMap(MtanTokenChangeDescription::getExistingToken).flatMap(SelectedMtanToken::getLabel);
      Optional<String> newPhoneNumber = change.flatMap(MtanTokenChangeDescription::getNewPhoneNumber).map(PhoneNumber::getValue).or(() -> existingPhoneNumber);
      Optional<String> newLabel = change.map(MtanTokenChangeDescription::getNewLabel)
         .flatMap(l -> !l.hasValue() ? existingLabel : Optional.ofNullable(l.value()));
      existingPhoneNumber.ifPresent(phoneNumber -> map.put("old-mtan-phone-number", phoneNumber));
      existingLabel.ifPresent(label -> map.put("old-mtan-label", label));
      newPhoneNumber.ifPresent(phoneNumber -> map.put("new-mtan-phone-number", phoneNumber));
      newLabel.ifPresent(label -> map.put("new-mtan-label", label));
   }

   private void addSelectedMtanTokenValues(Map<String, Object> map) {
      Optional<SelectedMtanToken> selectedMtanToken = ((FlowAttributeService)this.attributes.get()).findAttribute(SelectedMtanToken.class);
      selectedMtanToken.map(SelectedMtanToken::getPhoneNumber)
         .map(PhoneNumber::getValue)
         .ifPresent(phoneNumber -> map.put("selected-mtan-phone-number", phoneNumber));
      selectedMtanToken.flatMap(SelectedMtanToken::getLabel).ifPresent(label -> map.put("selected-mtan-label", label));
   }

   private void addDeletedMtanTokenValues(Map<String, Object> map) {
      Optional<SelectedMtanToken> tokenToBeDeleted = ((FlowAttributeService)this.attributes.get())
         .findAttribute(MtanTokenDeletionDescription.class)
         .map(MtanTokenDeletionDescription::getTokenToBeDeleted);
      tokenToBeDeleted.map(SelectedMtanToken::getPhoneNumber)
         .map(PhoneNumber::getValue)
         .ifPresent(phoneNumber -> map.put("deleted-mtan-phone-number", phoneNumber));
      tokenToBeDeleted.flatMap(SelectedMtanToken::getLabel).ifPresent(label -> map.put("deleted-mtan-label", label));
   }
}
