package com.airlock.iam.flow.shared.infrastructure.factory;

import com.airlock.iam.base.api.infrastructure.plugin.ModuleForConfig;
import com.airlock.iam.base.api.infrastructure.plugin.PluginConfigToLogic;
import com.airlock.iam.flow.api.domain.model.session.FlowAttributeRepository;
import com.airlock.iam.flow.shared.application.configuration.item.ContextDataItemDefinitionConfig;
import com.airlock.iam.flow.shared.application.configuration.item.EmailItemDefinitionConfig;
import com.airlock.iam.flow.shared.application.configuration.item.mtan.MtanLabelItemDefinitionConfig;
import com.airlock.iam.flow.shared.application.configuration.item.mtan.MtanNumberItemDefinitionConfig;
import com.airlock.iam.flow.shared.application.configuration.step.CommonDataEditStepConfig;
import com.airlock.iam.flow.shared.application.configuration.step.UserDataEditStepConfig;
import com.airlock.iam.flow.shared.domain.model.item.email.EmailItemDefinition;
import com.airlock.iam.flow.shared.domain.model.item.mtan.MtanNumberItems;
import com.airlock.iam.flow.shared.domain.model.step.data.ContextDataItems;
import com.airlock.iam.flow.shared.domain.model.step.data.UserDataEditChangeDescription;
import com.airlock.iam.flow.shared.domain.service.data.ContextDataItemsChangeServiceImpl;
import com.airlock.iam.flow.shared.domain.service.email.EmailChangeServiceImpl;
import com.airlock.iam.flow.shared.domain.service.mtan.MtanTokenChangeService;
import com.airlock.iam.flow.shared.domain.service.user.EditableItemChangeServiceList;
import com.airlock.iam.flow.shared.domain.service.user.EditableItemChangeServiceListImpl;
import com.google.inject.Exposed;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import java.util.Optional;
import java.util.stream.Collectors;

@ModuleForConfig(UserDataEditStepConfig.class)
public final class UserDataEditStepModule extends PrivateModule {
   @Provides
   @Exposed
   ContextDataItems provideContextDataItems(UserDataEditStepConfig config, PluginConfigToLogic toLogic) {
      return ContextDataItems.builder()
         .definitions(
            config.getUserDataItems()
               .stream()
               .filter(ContextDataItemDefinitionConfig.class::isInstance)
               .map(itemConfig -> toLogic.getLogic(itemConfig))
               .collect(Collectors.toList())
         )
         .build();
   }

   @Provides
   @Exposed
   MtanNumberItems provideMtanNumberItems(UserDataEditStepConfig config, PluginConfigToLogic toLogic) {
      return MtanNumberItems.builder()
         .numberItem(config.getUserDataItems().stream().filter(MtanNumberItemDefinitionConfig.class::isInstance).findFirst().map(toLogic::getLogic))
         .labelItem(config.getUserDataItems().stream().filter(MtanLabelItemDefinitionConfig.class::isInstance).findFirst().map(toLogic::getLogic))
         .build();
   }

   @Provides
   @Exposed
   Optional<EmailItemDefinition> provideEmailItemDefinition(UserDataEditStepConfig config, PluginConfigToLogic toLogic) {
      return config.getUserDataItems().stream().filter(EmailItemDefinitionConfig.class::isInstance).findFirst().map(toLogic::getLogic);
   }

   @Provides
   @Exposed
   UserDataEditChangeDescription provideChangeDescription(FlowAttributeRepository attributes) {
      Optional<UserDataEditChangeDescription> attribute = attributes.tryGetAttribute(UserDataEditChangeDescription.class);
      if (attribute.isPresent()) {
         return attribute.get();
      }

      UserDataEditChangeDescription newAttribute = UserDataEditChangeDescription.createNewChange();
      attributes.putOrMergeAttribute(newAttribute);
      return newAttribute;
   }

   @Provides
   @Exposed
   EditableItemChangeServiceList provideEditableItemChangeServiceList(
      ContextDataItemsChangeServiceImpl contextDataItemsChangeService,
      MtanTokenChangeService mtanRegistrationService,
      EmailChangeServiceImpl emailChangeService
   ) {
      return EditableItemChangeServiceListImpl.builder()
         .service(contextDataItemsChangeService)
         .service(mtanRegistrationService)
         .service(emailChangeService)
         .build();
   }

   @Provides
   @Exposed
   CommonDataEditStepConfig.NextDataEditActions provideNextDataEditActions() {
      return CommonDataEditStepConfig.DEFAULT_USER_DATA_EDIT_ACTIONS;
   }

   protected void configure() {
   }
}
