package com.airlock.iam.authentication.application.service.oauth2;

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.flow.api.domain.model.flow.FlowResult;
import com.airlock.iam.flow.application.service.flow.FlowTerminationService;
import com.airlock.iam.flow.shared.api.domain.model.session.UserSession;
import com.airlock.iam.oauth2.domain.model.validation.OAuth2Error;
import jakarta.inject.Inject;
import jakarta.inject.Provider;

public class OpenIdConnectPromptNoneFlowResultHandlerImpl implements OpenIdConnectPromptNoneFlowResultHandler {
   private static final ELogger LOG = ELoggerFactory.getLogger(OpenIdConnectPromptNoneFlowResultHandlerImpl.class);
   private final Provider<UserSession> userSession;
   private final Provider<FlowTerminationService> flowTerminationService;

   @Inject
   public OpenIdConnectPromptNoneFlowResultHandlerImpl(Provider<UserSession> userSession, Provider<FlowTerminationService> flowTerminationService) {
      this.userSession = userSession;
      this.flowTerminationService = flowTerminationService;
   }

   @Override
   public FlowResult handleFailedFlowResultForPromptNone(FlowResult result, OpenIdConnectPromptNoneFlowResultHandler.OAuth2FailureProvider failureProvider) {
      ((FlowTerminationService)this.flowTerminationService.get()).abortFlow();
      if (containsOAuth2Error(result)) {
         return result;
      } else if (result.hasInternalError()) {
         LOG.info("Internal error in flow, returning 'server error'.");
         return failureProvider.createOAuth2Failure(OAuth2Error.SERVER_ERROR, "Server error");
      } else if (result.isFailed() && result.nextStep().isEmpty()) {
         LOG.info("Flow failed, returning 'access denied'.");
         return failureProvider.createOAuth2Failure(OAuth2Error.ACCESS_DENIED, "Authentication failed");
      } else if (((UserSession)this.userSession.get()).userId().isPresent()) {
         LOG.info("Flow requires interaction, terminating flow and returning 'interaction required'.");
         return failureProvider.createOAuth2Failure(OAuth2Error.INTERACTION_REQUIRED, "Authentication requires interaction");
      } else {
         LOG.info("Flow requires interaction, terminating flow and returning 'login required'.");
         return failureProvider.createOAuth2Failure(OAuth2Error.LOGIN_REQUIRED, "Authentication required");
      }
   }

   private static boolean containsOAuth2Error(FlowResult result) {
      return result.error().isPresent()
         && result.error()
            .get()
            .name()
            .equals(OAuth2AuthorizationService.OAuth2AuthorizationEndpointErrors.OAUTH2_AUTHORIZATION_SERVER_INVALID_AUTHORIZATION_REQUEST.name());
   }
}
