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

import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FADeviceId;
import com.airlock.iam.authentication.infrastructure.transfer.request.Airlock2FARecoveryFlowBindingRequest;
import com.airlock.iam.flow.api.domain.model.flow.FlowResult;
import com.airlock.iam.flow.api.infrastructure.mapper.FlowResultMapper;
import com.airlock.iam.flow.auth.api.infrastructure.generated.transfer.response.AuthenticationFlowResultDataResourceDocument;
import com.airlock.iam.flow.shared.application.service.airlock2fa.Airlock2FARecovery;
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;

@Path("/airlock-2fa/recovery")
public class Airlock2FARecoveryAuthenticationFlowResource {
   private final Provider<Airlock2FARecovery> airlock2faRecovery;
   private final FlowResultMapper mapper;

   @Inject
   public Airlock2FARecoveryAuthenticationFlowResource(Provider<Airlock2FARecovery> airlock2faRecovery, FlowResultMapper mapper) {
      this.airlock2faRecovery = airlock2faRecovery;
      this.mapper = mapper;
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "Further steps required.\n<br>Next step: <tt>AIRLOCK_2FA_RECOVERY_REQUIRED</tt> (as documented <a href=\"#nextAuthStepCodes\">here</a>).\n",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class)),
                     @Content(mediaType = "application/json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class))
               }
            ),
            @ApiResponse(
               responseCode = "403",
               description = "<div class=\"iam-error-code\"><table>\n<tr>\n<td>AIRLOCK_2FA_RECOVERY_DEVICES_INVALID</td>\n<td>The provided devices are invalid. Exactly one of the provided identifiers has to correspond to a device of the current user.</td>\n</tr>\n</table>\n</div>\n<br>The current authentication flow has been aborted.\n<br>Possible next step: none.\n",
               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 the recovery of one or multiple Airlock 2FA devices with Trusted Session Binding.\nOne installation of an Airlock 2FA App can be enrolled for different users.\nEach of these enrollments represents one (virtual) Airlock 2FA Device.\nAll the devices on one Airlock 2FA App installation have to be recovered at the same time.\nIf multiple of these devices require Trusted Session Binding, all of their identifiers have to\nbe provided to this endpoint.\n<div class=\"iam-resource-return\">The Trusted Session Binding token (as part of the additional attributes, as documented <a href=\"#additionalAuthAttributes\">here</a>).</div>",
      tags = "Airlock 2FA",
      summary = "Start recovery"
   )
   @POST
   @Path("/start")
   @Consumes("application/json")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response startRecovery(
      @Parameter(description = "Contains the identifiers of the devices to be recovered.") @NotNull @Valid Airlock2FARecoveryFlowBindingRequest request
   ) {
      FlowResult flowResult = ((Airlock2FARecovery)this.airlock2faRecovery.get())
         .startRecovery(request.getDeviceIds().stream().<Airlock2FADeviceId>map(Airlock2FADeviceId::airlock2FADeviceId).toList());
      return this.mapper.toResponse(flowResult);
   }

   @ApiResponse(
      responseCode = "200",
      description = "Step completed or further steps required, such as further polling.\n<br>Possible next step: <tt>AIRLOCK_2FA_RECOVERY_REQUIRED</tt> (as documented <a href=\"#nextAuthStepCodes\">here</a>).\n",
      content = {
            @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class)),
            @Content(mediaType = "application/json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class))
      }
   )
   @Operation(
      description = "Polls the Airlock 2FA recovery status.\n<div class=\"iam-resource-return\">The status of the Airlock 2FA recovery.\n If the attribute <tt>nextAuthStep</tt> is present in the response, further steps are required to successfully authenticate.\n If the attribute is missing, the user is successfully authenticated.</div>",
      tags = "Airlock 2FA",
      summary = "Poll recovery"
   )
   @POST
   @Path("/status/poll")
   @Consumes("application/json")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response pollRecoveryStatus() {
      FlowResult flowResult = ((Airlock2FARecovery)this.airlock2faRecovery.get()).pollRecoveryResult();
      return this.mapper.toResponse(flowResult);
   }
}
