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

import ch.ergon.restal.jsonapi.document.error.ErrorData;
import com.airlock.iam.base.api.domain.model.validation.ValidationResult;
import com.airlock.iam.common.domain.model.password.PasswordImpl;
import com.airlock.iam.flow.api.domain.model.flow.FlowResult;
import com.airlock.iam.flow.api.infrastructure.mapper.FlowResultMapper;
import com.airlock.iam.flow.infrastructure.mapper.ValidationResultMapper;
import com.airlock.iam.flow.shared.infrastructure.mapper.PasswordPolicyViolationDataMapper;
import com.airlock.iam.publicselfservice.api.infrastructure.generated.transfer.response.PublicSelfServiceFlowResultDataResourceDocument;
import com.airlock.iam.publicselfservice.application.service.PasswordReset;
import com.airlock.iam.publicselfservice.infrastructure.transfer.request.SetPasswordRequest;
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.List;

@Path("/password")
public class PublicSelfServiceSetPasswordResource {
   private final Provider<PasswordReset> passwordReset;
   private final FlowResultMapper mapper;
   private final Provider<ValidationResultMapper> stepErrorResultMapper;

   @Inject
   public PublicSelfServiceSetPasswordResource(
      Provider<PasswordReset> passwordReset, FlowResultMapper mapper, Provider<ValidationResultMapper> stepErrorResultMapper
   ) {
      this.passwordReset = passwordReset;
      this.mapper = mapper;
      this.stepErrorResultMapper = stepErrorResultMapper;
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "Password has been successfully set.",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = PublicSelfServiceFlowResultDataResourceDocument.class)),
                     @Content(mediaType = "application/json", schema = @Schema(implementation = PublicSelfServiceFlowResultDataResourceDocument.class))
               }
            ),
            @ApiResponse(
               responseCode = "400",
               description = "<div class=\"iam-error-code\"><table>\n<tr>\n<td>PASSWORD_POLICY_VIOLATED</td>\n<td>The new password violates the password policy. See <a href=\"#passwordPolicyDetailCodes\">password policy violation detail codes</a>.</td>\n</tr>\n</table>\n</div>\n<br>Possible next step: <tt>NEW_PASSWORD_REQUIRED</tt> (as documented <a href=\"#nextPublicSelfServiceStepCodes\">here</a>).\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"))
               }
            ),
            @ApiResponse(
               responseCode = "403",
               description = "<div class=\"iam-error-code\"><table>\n<tr>\n<td>NOT_ALLOWED</td>\n<td>The user is not allowed to reset the password.</td>\n</tr>\n</table>\n</div>\n<br>The current public self-service 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 = "Sets the new password.\n<div class=\"iam-resource-return\">Whether the new password has been successfully set. The attribute <tt>nextStep</tt> in the response\n indicates the next step required for the public self-service.</div>",
      tags = "Password",
      summary = "Set password"
   )
   @POST
   @Path("/set")
   @Consumes("application/json")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response setPassword(@Parameter(description = "Contains the new password.") @NotNull @Valid SetPasswordRequest request) {
      FlowResult result = ((PasswordReset)this.passwordReset.get()).setPassword(PasswordImpl.passwordOf(request.getNewPassword()));
      ValidationResult validationResult = PasswordPolicyViolationDataMapper.validatePasswordPolicy(result, "newPassword");
      if (!validationResult.isValid()) {
         List<ErrorData> errors = ((ValidationResultMapper)this.stepErrorResultMapper.get()).toErrorData(result.error().get(), validationResult);
         return this.mapper.toResponse(result, errors);
      } else {
         return this.mapper.toResponse(result);
      }
   }
}
