package com.airlock.iam.authentication.infrastructure.resource;

import com.airlock.iam.authentication.application.service.devicetoken.AuthDeviceTokenRegistration;
import com.airlock.iam.authentication.infrastructure.transfer.request.DeviceTokenRegistrationRequest;
import com.airlock.iam.flow.api.domain.model.flow.FlowResult;
import com.airlock.iam.flow.auth.api.infrastructure.generated.transfer.response.AuthenticationFlowResultDataResourceDocument;
import com.airlock.iam.flow.infrastructure.mapper.ValidationResultMapper;
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.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
import java.util.Optional;

@Path("/device-token")
public class DeviceTokenRegistrationAuthFlowResource {
   private final Provider<ValidationResultMapper> validationResultMapper;
   private final Provider<AuthDeviceTokenRegistration> registration;

   @Inject
   public DeviceTokenRegistrationAuthFlowResource(Provider<ValidationResultMapper> validationResultMapper, Provider<AuthDeviceTokenRegistration> registration) {
      this.validationResultMapper = validationResultMapper;
      this.registration = registration;
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "Device token registration successfully started.",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class)),
                     @Content(mediaType = "application/json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class))
               }
            ),
            @ApiResponse(
               responseCode = "400",
               description = "The supplied attributes could not be validated (wrong key type, wrong key length, or missing attribute).",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(ref = "json-api.yaml#/components/schemas/ErrorDocumentResponse")),
                     @Content(mediaType = "application/json", schema = @Schema(ref = "json-api.yaml#/components/schemas/ErrorDocumentResponse"))
               }
            )
      }
   )
   @Operation(
      description = "Starts a device token registration during an authentication flow.\n<p>\nRegister a new device token by providing a JSON Web Key (JWK) public key and optionally a label and/or a serial ID of the device.\nThe device token is only persisted if a subsequent \"Apply Changes Step\"\nwith an \"Apply Device Token Registration\" handler is configured.\n</p>\n<p>\nThe public key is represented as specified in JWK (RFC7517). Currently elliptic curve signatures (keys of type \"EC\") are supported.<br/>\nThe following attributes are expected in the public key attribute (according to the JWK specification):\n<ul>\n<li>\"crv\" - the elliptic curve. Supported values are:\n<ul>\n<li>\"P-256\": for ES256 signatures</li>\n<li>\"P-256K\": for ES256K signatures</li>\n<li>\"P-384\": for ES384 signatures</li>\n<li>\"P-521\": for ES512 signatures</li>\n</ul>\nPlease note: During registration all four values are always allowed, but for the other use cases of device tokens (e.g. authentication)\nit is possible to restrict (in the IAM configuration) which curves are allowed.</li>\n<li>\"x\" - the x coordinate of the base point.</li>\n<li>\"y\" - the y coordinate of the base point.</li>\n<li>\"kty\" - the key type - must be \"EC\"</li>\n<li>\"kid\" - a key identifier (optional)</li>\n</ul>\n</p>\n<div class=\"iam-resource-return\">If the attribute <tt>nextAuthStep</tt> is present in the response, further steps are required.\n If the attribute is missing, the registration has been successfully completed.</div>",
      tags = "Device Tokens",
      summary = "Start token registration"
   )
   @POST
   @Path("/registration/start")
   @Consumes({"application/vnd.api+json", "application/json"})
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response registerDeviceToken(
      @Parameter(description = "A request to start a registration for a new device token (public key, optionally label and serial).") @NotNull @Valid DeviceTokenRegistrationRequest request
   ) {
      FlowResult flowResult = ((AuthDeviceTokenRegistration)this.registration.get())
         .registerDeviceToken(Optional.ofNullable(request.getSerial()), Optional.ofNullable(request.getLabel()), request.getPublicJwk());
      return ((ValidationResultMapper)this.validationResultMapper.get()).toValidationResponse(flowResult);
   }
}
