package com.airlock.iam.authentication.infrastructure.service.ui;

import com.airlock.iam.authentication.api.domain.model.password.UsernamePasswordAuthenticationStep;
import com.airlock.iam.authentication.api.domain.model.step.UserIdentifyingStep;
import com.airlock.iam.authentication.application.configuration.fido.FidoAuthenticationStepActions;
import com.airlock.iam.authentication.application.configuration.ui.LinkConfigurationAuthenticationStepUiConfig;
import com.airlock.iam.authentication.domain.model.airlock2fa.Airlock2FAUsernamelessQrCodeAuthenticationStep;
import com.airlock.iam.authentication.domain.model.identification.UserIdentifyingFidoStep;
import com.airlock.iam.authentication.domain.model.password.PasswordAuthenticationStep;
import com.airlock.iam.authentication.domain.model.password.UsernamePasswordFidoStep;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.api.infrastructure.plugin.PluginConfigToLogic;
import com.airlock.iam.base.domain.service.uri.UrlUtils;
import com.airlock.iam.flow.api.domain.model.step.StepAction;
import com.airlock.iam.flow.ui.application.configuration.PublicSelfServiceLinkConfig;
import com.airlock.iam.flow.ui.application.configuration.UserSelfRegLinkConfig;
import com.airlock.iam.flow.ui.infrastructure.service.LinkTarget;
import com.airlock.iam.flow.ui.infrastructure.service.ui.GlobalUiAttributes;
import com.airlock.iam.flow.ui.infrastructure.service.ui.StepUiService;
import com.airlock.iam.flow.ui.infrastructure.settings.AdditionalAuthenticationTargetSettings;
import com.airlock.iam.flow.ui.infrastructure.settings.AdditionalAuthenticationTargetsSettings;
import com.airlock.iam.flow.ui.infrastructure.settings.SimpleDefaultUiSettings;
import com.airlock.iam.flow.ui.infrastructure.settings.StepUiSettings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@LogicForConfig(LinkConfigurationAuthenticationStepUiConfig.class)
public class LinkConfigurationAuthenticationStepUiService implements StepUiService {
   private static final String APPLICATION_ACCESS_PATH = "{{SPA}}/auth/application/access";
   private static final Map<String, String> STEP_ACTIONS_TO_PAGE_ID = Map.of(
      UsernamePasswordAuthenticationStep.UsernamePasswordStepActions.PASSWORD_REQUIRED.name(),
      "password",
      PasswordAuthenticationStep.PasswordStepActions.PASSWORD_ONLY_REQUIRED.name(),
      "password-only",
      UsernamePasswordFidoStep.UsernamePasswordFidoStepActions.PASSWORD_OR_FIDO_REQUIRED.name(),
      "password/fido",
      UserIdentifyingStep.UserIdentifyingStepAction.USERNAME_REQUIRED.name(),
      "username",
      UserIdentifyingFidoStep.UserIdentifyingFidoStepAction.USERNAME_OR_FIDO_REQUIRED.name(),
      "username/fido",
      FidoAuthenticationStepActions.Action.FIDO_AUTHENTICATION_CHALLENGE_RETRIEVAL_REQUIRED.name(),
      "fido/passwordless",
      FidoAuthenticationStepActions.Action.FIDO_AUTHENTICATION_ASSERTION_RESPONSE_REQUIRED.name(),
      "fido/passwordless",
      Airlock2FAUsernamelessQrCodeAuthenticationStep.Airlock2FAUsernamelessQrCodeStepActions.AIRLOCK_2FA_USERNAMELESS_POLLING_REQUIRED.name(),
      "airlock-2fa/usernameless"
   );
   private final LinkConfigurationAuthenticationStepUiConfig config;
   private final PluginConfigToLogic toLogic;
   private final Provider<GlobalUiAttributes> globalUiAttributes;

   @Inject
   public LinkConfigurationAuthenticationStepUiService(
      LinkConfigurationAuthenticationStepUiConfig config, PluginConfigToLogic toLogic, Provider<GlobalUiAttributes> globalUiAttributes
   ) {
      this.config = config;
      this.toLogic = toLogic;
      this.globalUiAttributes = globalUiAttributes;
   }

   public StepUiSettings toSettings(StepAction currentStepAction) {
      String pageId = STEP_ACTIONS_TO_PAGE_ID.getOrDefault(currentStepAction.toString(), "password");
      SimpleDefaultUiSettings settings = SimpleDefaultUiSettings.builder()
         .pageId(pageId)
         .stepId(this.config.getStepId())
         .uiTenantId(((GlobalUiAttributes)this.globalUiAttributes.get()).uiTenantId())
         .build();
      this.setUserSelfRegistrationLink(settings);
      this.setPublicSelfServiceLink(settings);
      this.setAdditionalAuthenticationButtons(settings);
      return settings;
   }

   private void setUserSelfRegistrationLink(SimpleDefaultUiSettings settings) {
      UserSelfRegLinkConfig linkConfig = this.config.getUserSelfRegistrationLink();
      if (linkConfig != null) {
         LinkTarget selfRegRegistrationLink = this.toLogic.getLogic(linkConfig);
         settings.getPageSettings().put("userSelfRegistrationLink", selfRegRegistrationLink.getLinkUrl());
      }
   }

   private void setPublicSelfServiceLink(SimpleDefaultUiSettings settings) {
      PublicSelfServiceLinkConfig linkConfig = this.config.getPublicSelfServiceLink();
      if (linkConfig != null) {
         LinkTarget publicSelfServiceLink = this.toLogic.getLogic(linkConfig);
         settings.getPageSettings().put("publicSelfServiceLink", publicSelfServiceLink.getLinkUrl());
      }
   }

   private void setAdditionalAuthenticationButtons(SimpleDefaultUiSettings settings) {
      List<AdditionalAuthenticationTargetSettings> linkTargets = this.config.getAdditionalAuthenticationButtons().stream().map(link -> {
         String applicationId = link.getId().getApplicationId();
         String redirectTargetUrl = "{{SPA}}/auth/application/access/" + UrlUtils.urlEncodePathSegment(applicationId);
         return new AdditionalAuthenticationTargetSettings(applicationId, redirectTargetUrl);
      }).collect(Collectors.toList());
      settings.getPageSettings().put("additionalAuthenticationButtons", new AdditionalAuthenticationTargetsSettings(linkTargets));
   }
}
