package com.airlock.iam.oauth2.infrastructure.resource.rest;

import com.airlock.iam.common.api.infrastructure.annotation.DisableCsrfFilter;
import com.airlock.iam.oauth2.application.service.token.OAuth2TokenEndpointService;
import com.airlock.iam.oauth2.infrastructure.validation.AuthorizationServerIdValidator;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;

@Path("/authorization-servers/{authorizationServerId}/token")
public class OAuth2TokenEndpointResource {
   private final Provider<OAuth2TokenEndpointService> tokenEndpointService;
   private final Provider<HttpServletResponse> response;
   private final Provider<AuthorizationServerIdValidator> authorizationServerIdValidator;

   @Inject
   public OAuth2TokenEndpointResource(
      Provider<OAuth2TokenEndpointService> tokenEndpointService,
      Provider<HttpServletResponse> response,
      Provider<AuthorizationServerIdValidator> authorizationServerIdValidator
   ) {
      this.tokenEndpointService = tokenEndpointService;
      this.response = response;
      this.authorizationServerIdValidator = authorizationServerIdValidator;
   }

   @ApiResponses(
      {
            @ApiResponse(responseCode = "200", description = "The request was processed successfully and the response contains the requested token(s)."),
            @ApiResponse(
               responseCode = "400",
               description = "An error has occurred and the response body may contain an error object.",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(ref = "json-api.yaml#/components/schemas/ErrorDocumentResponse")),
                     @Content(mediaType = "application/json", schema = @Schema(ref = "#/components/schemas/OAuth2ErrorResponse"))
               }
            ),
            @ApiResponse(
               responseCode = "404",
               description = "<div class=\"iam-error-code\"><table>\n<tr>\n<td>AUTHORIZATION_SERVER_NOT_FOUND</td>\n<td>The authorization server ID does not exist.</td>\n</tr>\n</table>\n</div>\n",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(ref = "json-api.yaml#/components/schemas/ErrorDocumentResponse")),
                     @Content(mediaType = "application/json", schema = @Schema(ref = "#/components/schemas/OAuth2ErrorResponse"))
               }
            )
      }
   )
   @POST
   @Operation(
      description = "The token endpoint is used by the client to obtain an access token\nand refresh token by presenting its authorization grant or refresh token.\nThe token endpoint is used with every authorization grant except for the\nimplicit grant type (since an access token is issued directly).\n<div class=\"iam-docu\">\n<table>\n<tr><th>Use-Case</th><th>Format</th><th>RFC Reference</th></tr>\n<tr><td>OAuth 2.0 / OpenID Connect: Authorization Code Grant</td><td>Access Token Request</td><td>see <a href=\"https://tools.ietf.org/html/rfc6749#section-4.1.3\" target=\"_blank\">RFC 6749, Chapter 4.1.3</a></td></tr>\n<tr><td>OAuth 2.0 / OpenID Connect: Authorization Code Grant</td><td>Access Token Refresh</td><td>see <a href=\"https://tools.ietf.org/html/rfc6749#section-6\" target=\"_blank\">RFC 6749, Chapter 6</a></td></tr>\n<tr><td>OAuth 2.0 Client Credentials Grant</td><td>Access Token Request</td><td>see <a href=\"https://tools.ietf.org/html/rfc6749#section-4.4.2\" target=\"_blank\">RFC 6749, Chapter 4.4.2</a></td></tr>\n</table>\n</div>",
      tags = "OAuth 2.0/OIDC",
      summary = "Get tokens",
      requestBody = @RequestBody(
         description = "Refer to the referenced RFCs in the use-case table above to see which form parameters must be provided.",
         content = @Content(
            mediaType = "application/x-www-form-urlencoded",
            schema = @Schema(additionalProperties = AdditionalPropertiesValue.TRUE, type = "object")
         )
      )
   )
   @Consumes("application/x-www-form-urlencoded")
   @Produces("application/json")
   @DisableCsrfFilter
   public Response tokenEndpoint(
      @Parameter(description = "The authorization server ID.") @PathParam("authorizationServerId") String authorizationServerId,
      MultivaluedMap<String, String> formParams
   ) {
      ((AuthorizationServerIdValidator)this.authorizationServerIdValidator.get()).validateAuthorizationServer(authorizationServerId);
      if (formParams == null) {
         formParams = new MultivaluedHashMap();
      }

      ((OAuth2TokenEndpointService)this.tokenEndpointService.get()).handleTokenEndpoint(formParams);
      return Response.status(((HttpServletResponse)this.response.get()).getStatus()).build();
   }
}
