package com.airlock.iam.oauth2.domain.model.response;

import com.airlock.iam.oauth2.api.domain.model.OAuth2ClientId;
import com.airlock.iam.oauth2.domain.model.OAuth2Response;
import com.airlock.iam.oauth2.domain.model.OAuth2ResponseMode;
import com.airlock.iam.oauth2.domain.model.State;
import com.airlock.iam.oauth2.domain.model.session.OpenIDProviderUserAgentState;
import com.airlock.iam.oauth2.domain.model.session.OpenIdConnectSessionStateCalculator;
import com.airlock.iam.oauth2.domain.model.validation.OAuth2Error;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URI;
import java.util.Optional;

public final class OAuth2ErrorResponseBuilder {
   private final OpenIdConnectSessionStateCalculator sessionStateCalculator;
   private final OAuth2ClientId clientId;
   private final URI authorizationRequestRedirectUri;
   private final Optional<State> authorizationRequestState;
   private final OAuth2ResponseMode responseMode;

   public static OAuth2ErrorResponseBuilder errorResponseBuilder(
      Optional<OpenIDProviderUserAgentState> openIDProviderUserAgentState,
      OAuth2ClientId clientId,
      URI redirectUri,
      Optional<State> authorizationRequestState,
      OAuth2ResponseMode responseMode
   ) {
      return new OAuth2ErrorResponseBuilder(
         new OpenIdConnectSessionStateCalculator(openIDProviderUserAgentState), clientId, redirectUri, authorizationRequestState, responseMode
      );
   }

   public OAuth2Response buildResponse(OAuth2Error error) {
      return this.buildErrorRedirect(error, Optional.empty());
   }

   public OAuth2Response buildResponse(OAuth2Error error, String errorDescription) {
      return this.buildErrorRedirect(error, Optional.of(errorDescription));
   }

   private OAuth2Response buildErrorRedirect(OAuth2Error error, Optional<String> errorDescription) {
      OAuth2ResponseBuilder oAuth2ResponseBuilder = new OAuth2ResponseBuilder(this.authorizationRequestRedirectUri, this.responseMode)
         .addError(error.getParameterValue());
      this.authorizationRequestState.map(State::getState).ifPresent(oAuth2ResponseBuilder::addState);
      errorDescription.ifPresent(oAuth2ResponseBuilder::addErrorDescription);
      this.sessionStateCalculator
         .sessionState(this.authorizationRequestRedirectUri.toASCIIString(), this.clientId)
         .ifPresent(oAuth2ResponseBuilder::addSessionState);
      return oAuth2ResponseBuilder.buildResponse();
   }

   @SuppressFBWarnings(justification = "generated code")
   private OAuth2ErrorResponseBuilder(
      OpenIdConnectSessionStateCalculator sessionStateCalculator,
      OAuth2ClientId clientId,
      URI authorizationRequestRedirectUri,
      Optional<State> authorizationRequestState,
      OAuth2ResponseMode responseMode
   ) {
      this.sessionStateCalculator = sessionStateCalculator;
      this.clientId = clientId;
      this.authorizationRequestRedirectUri = authorizationRequestRedirectUri;
      this.authorizationRequestState = authorizationRequestState;
      this.responseMode = responseMode;
   }
}
