package com.airlock.iam.login.rest.infrastructure.resource.pub;

import com.airlock.iam.common.api.infrastructure.annotation.DisableCsrfFilter;
import com.airlock.iam.common.api.infrastructure.annotation.RequiresWritableSession;
import com.airlock.iam.common.application.service.JwksService;
import com.airlock.iam.common.domain.model.jwk.JsonWebKeySet;
import com.airlock.iam.common.infrastructure.response.CacheControlResponseHeaderService;
import com.airlock.iam.login.rest.infrastructure.transfer.documentation.JwksResponseData;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
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.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.ResponseBuilder;
import jakarta.ws.rs.core.Response.Status;
import java.util.Optional;

@Path("/")
public final class JwksResource {
   private static final String JWKS_EXAMPLE = "{\n\t\"keys\" : [\n\t\t{\n\t\t\t\"kty\" : \"EC\",\n\t\t\t\"use\" : \"sig\",\n\t\t\t\"crv\" : \"P-521\",\n\t\t\t\"kid\" : \"489600a1536e946749ed99e59105018d84713a90\",\n\t\t\t\"x\" : \"AQvgoB_NfBuBOWZE_3ONQUxLRiE02uekRxLgQTfTXZuEvYAOGUWZX2OHAyR-n9jM0gKEyQjArl7OhZEB8aNMmpqo\",\n\t\t\t\"y\" : \"Aftx9XvorV7I7tvfP1doqjzJLnFacSPGYDwNXA1icvGhtObjA1zsUHOQfzP5zeIzC9hSKgqcpdjmrEWipFiN9JTA\",\n\t\t\t\"alg\":\"ES512\"\n\t\t},\n\t\t{\n\t\t\t\"kty\" : \"RSA\",\n\t\t\t\"e\" : \"AQAB\",\n\t\t\t\"use\" : \"sig\",\n\t\t\t\"kid\" : \"729649aacb86a3af49f7bcfeeb2b018d83c410e4\",\n\t\t\t\"alg\" : \"RS256\",\n\t\t\t\"n\" : \"6NWRqi5AuwbjN8-PdkXHmH9Irtr8xlYZmAQtvXVPOX4Q6I_wQA05v2Zwpu8glm_cqHMRPUDywjDMFxCszoeFf9kViQ-bXt-xi-pZyfAo5Nu0KPtu1zaz1vF4aSqXybUV-6xq2L5P2uL_RSScUaJ-cqj09wHya6SXHEtl9WUqqYqcoP2as351PeguktunXxmqjVxfYuXzk6w5KuKunNfT1pgk9Z8hCgmaArHVc9Ane6xlMr4Nkz7hrJoBaoxi7MXBdGitpeBzNQhx5JR1ISN9CIbcsNaY5mJS4j7T6QbUXkNDKQz7cfKQQ5JHYl0gHTxDNvBVXNAXokCZlz_wutHdXw\"\n\t\t}\n\t]\n}\n";
   private final Provider<Optional<JwksService>> jwksService;
   private final Provider<CacheControlResponseHeaderService> cacheControlResponseHeaderService;

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "The JWKS has been returned successfully.",
               content = @Content(
                  mediaType = "application/json",
                  schema = @Schema(implementation = JwksResponseData.class),
                  examples = @ExampleObject(
                     name = "A JWK Set",
                     value = "{\n\t\"keys\" : [\n\t\t{\n\t\t\t\"kty\" : \"EC\",\n\t\t\t\"use\" : \"sig\",\n\t\t\t\"crv\" : \"P-521\",\n\t\t\t\"kid\" : \"489600a1536e946749ed99e59105018d84713a90\",\n\t\t\t\"x\" : \"AQvgoB_NfBuBOWZE_3ONQUxLRiE02uekRxLgQTfTXZuEvYAOGUWZX2OHAyR-n9jM0gKEyQjArl7OhZEB8aNMmpqo\",\n\t\t\t\"y\" : \"Aftx9XvorV7I7tvfP1doqjzJLnFacSPGYDwNXA1icvGhtObjA1zsUHOQfzP5zeIzC9hSKgqcpdjmrEWipFiN9JTA\",\n\t\t\t\"alg\":\"ES512\"\n\t\t},\n\t\t{\n\t\t\t\"kty\" : \"RSA\",\n\t\t\t\"e\" : \"AQAB\",\n\t\t\t\"use\" : \"sig\",\n\t\t\t\"kid\" : \"729649aacb86a3af49f7bcfeeb2b018d83c410e4\",\n\t\t\t\"alg\" : \"RS256\",\n\t\t\t\"n\" : \"6NWRqi5AuwbjN8-PdkXHmH9Irtr8xlYZmAQtvXVPOX4Q6I_wQA05v2Zwpu8glm_cqHMRPUDywjDMFxCszoeFf9kViQ-bXt-xi-pZyfAo5Nu0KPtu1zaz1vF4aSqXybUV-6xq2L5P2uL_RSScUaJ-cqj09wHya6SXHEtl9WUqqYqcoP2as351PeguktunXxmqjVxfYuXzk6w5KuKunNfT1pgk9Z8hCgmaArHVc9Ane6xlMr4Nkz7hrJoBaoxi7MXBdGitpeBzNQhx5JR1ISN9CIbcsNaY5mJS4j7T6QbUXkNDKQz7cfKQQ5JHYl0gHTxDNvBVXNAXokCZlz_wutHdXw\"\n\t\t}\n\t]\n}\n"
                  )
               )
            ),
            @ApiResponse(responseCode = "501", description = "JWKS is not configured.")
      }
   )
   @GET
   @Operation(
      description = "Returns the JSON Web Key (JWK) Set document of IAM Loginapp.\n<div class=\"iam-resource-return\">A JWK Set containing all keys used by IAM Loginapp to sign JWTs.</div>",
      tags = "Signing Keys",
      summary = "Get JWK Set"
   )
   @Path("jwks")
   @Produces("application/json")
   @DisableCsrfFilter
   @RequiresWritableSession
   public Response getJwks(@Context ContainerRequestContext requestContext) {
      return ((Optional)this.jwksService.get())
         .map(JwksService::jsonWebKeySet)
         .map(JsonWebKeySet::toJson)
         .<ResponseBuilder>map(Response::ok)
         .map(
            responseBuilder -> ((CacheControlResponseHeaderService)this.cacheControlResponseHeaderService.get())
               .setCacheControlHeader(responseBuilder, requestContext)
         )
         .<Response>map(ResponseBuilder::build)
         .orElseGet(JwksResource::logInfoAndReturnNotImplemented);
   }

   @Inject
   public JwksResource(Provider<Optional<JwksService>> jwksService, Provider<CacheControlResponseHeaderService> cacheControlResponseHeaderService) {
      this.jwksService = jwksService;
      this.cacheControlResponseHeaderService = cacheControlResponseHeaderService;
   }

   private static Response logInfoAndReturnNotImplemented() {
      return Response.status(Status.NOT_IMPLEMENTED).build();
   }
}
