package com.airlock.iam.flow.shared.application.service.identification;

import com.airlock.iam.authentication.api.domain.model.step.UserIdentifyingStep;
import com.airlock.iam.flow.api.domain.model.flow.FlowResult;
import com.airlock.iam.flow.api.domain.model.step.GenericStepError;
import com.airlock.iam.flow.api.domain.model.step.StepResult;
import com.airlock.iam.flow.domain.model.flow.FlowProvider;
import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
import java.util.Collections;
import java.util.Map;

public final class UserIdentification {
   private final FlowProvider flowProvider;

   @Inject
   public UserIdentification(FlowProvider flowProvider) {
      this.flowProvider = flowProvider;
   }

   public FlowResult identifyUser(@Nullable String username, @Nullable Map<String, String> userData) {
      return this.flowProvider.getCurrentOrStartNew().execute(step -> selectAndExecuteUserIdentification(username, userData, step), UserIdentifyingStep.class);
   }

   private static StepResult selectAndExecuteUserIdentification(String username, Map<String, String> userData, UserIdentifyingStep step) {
      if (noneProvided(username, userData)) {
         return step.identifyUserByUserData(Collections.emptyMap());
      } else {
         return bothProvided(username, userData)
            ? step.stepResultFactory().failRetry(GenericStepError.VALIDATION_FAILED, step.stepAction()).build()
            : identifyUser(username, userData, step);
      }
   }

   private static StepResult identifyUser(String username, Map<String, String> userData, UserIdentifyingStep step) {
      return username != null ? step.identifyUser(username) : step.identifyUserByUserData(userData);
   }

   private static boolean bothProvided(String username, Map<String, String> userData) {
      return username != null && userData != null;
   }

   private static boolean noneProvided(String username, Map<String, String> userData) {
      return username == null && userData == null;
   }
}
