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

import ch.ergon.restal.jsonapi.document.data.ResourceDocument;
import ch.ergon.restal.jsonapi.document.data.ResourceObject;
import com.airlock.iam.common.api.domain.model.secretquestions.SecretQuestionsAnswer;
import com.airlock.iam.common.application.jsonapi.ResourceIdentifierUtils;
import com.airlock.iam.flow.api.domain.model.flow.FlowResult;
import com.airlock.iam.flow.api.infrastructure.mapper.FlowResultMapper;
import com.airlock.iam.publicselfservice.api.infrastructure.generated.transfer.response.PublicSelfServiceFlowResultDataResourceDocument;
import com.airlock.iam.publicselfservice.application.service.SecretQuestionsIdentityVerification;
import com.airlock.iam.publicselfservice.domain.model.step.SecretQuestionsIdentityVerificationStep;
import com.airlock.iam.publicselfservice.infrastructure.generated.transfer.PublicSelfServiceSecretQuestionsChallengeDataResourceDocument;
import com.airlock.iam.publicselfservice.infrastructure.transfer.PublicSelfServiceSecretQuestionsChallengeData;
import com.airlock.iam.publicselfservice.infrastructure.transfer.request.SecretQuestionsVerificationRequest;
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.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import ma.glasnost.orika.MapperFacade;

@Path("/verification/secret-questions")
public class PublicSelfServiceSecretQuestionsResource {
   private final FlowResultMapper mapper;
   private final MapperFacade mapperFacade;
   private final Provider<SecretQuestionsIdentityVerification> secretQuestionsCheck;

   @Inject
   public PublicSelfServiceSecretQuestionsResource(
      FlowResultMapper mapper, MapperFacade mapperFacade, Provider<SecretQuestionsIdentityVerification> mtanVerification
   ) {
      this.mapper = mapper;
      this.mapperFacade = mapperFacade;
      this.secretQuestionsCheck = mtanVerification;
   }

   @ApiResponse(
      responseCode = "200",
      description = "The questions have been successfully returned.",
      content = {
            @Content(
               mediaType = "application/vnd.api+json",
               schema = @Schema(implementation = PublicSelfServiceSecretQuestionsChallengeDataResourceDocument.class)
            ),
            @Content(mediaType = "application/json", schema = @Schema(implementation = PublicSelfServiceSecretQuestionsChallengeDataResourceDocument.class))
      }
   )
   @Deprecated
   @Operation(
      tags = "Secret Questions",
      description = "> [!caution]\n> This endpoint is deprecated. The list of available questions are returned as\n<a href=\"#additionalPublicSelfServiceAttributes\">additional attributes</a> with the <tt>SECRET_QUESTIONS_ANSWER_REQUIRED</tt> next step code.\n<p>Retrieves secret questions which have to be answered.</p>\n<div class=\"iam-resource-return\">A list of secret question resource keys.</div>",
      summary = "List questions"
   )
   @Path("retrieve")
   @POST
   @Consumes("application/json")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response retrieveQuestions() {
      FlowResult result = ((SecretQuestionsIdentityVerification)this.secretQuestionsCheck.get()).retrieveQuestions();
      if (result.isFailed()) {
         return this.mapper.toResponse(result);
      }

      SecretQuestionsIdentityVerificationStep.SecretQuestions challenge = result.<SecretQuestionsIdentityVerificationStep.SecretQuestions>data().get();
      PublicSelfServiceSecretQuestionsChallengeData attributes = (PublicSelfServiceSecretQuestionsChallengeData)this.mapperFacade
         .map(challenge, PublicSelfServiceSecretQuestionsChallengeData.class);
      ResourceDocument<PublicSelfServiceSecretQuestionsChallengeData> document = ResourceObject.builder(
            ResourceIdentifierUtils.getIdFor(attributes), attributes
         )
         .document();
      return Response.ok(document).build();
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "Answers successfully verified.",
               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\t *\n<tr>\n<td>ANSWER_WRONG</td>\n<td>Answers could not be validated successfully. Retry with correct answers.</td>\n</tr>\n</table>\n</div>\n<br>Possible next step: <tt>SECRET_QUESTIONS_ANSWER_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>ANSWER_WRONG</td>\n<td>Answers could not be validated successfully and no retries are allowed.</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 = "Checks the answers to secret questions. Note that unlike approval REST calls, identity verification does not require an existing user\nand supports stealth mode.\n<div class=\"iam-resource-return\">Whether the answers were accepted.</div>",
      tags = "Secret Questions",
      summary = "Check answers"
   )
   @Path("answer")
   @POST
   @Consumes("application/json")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response verifySecretQuestions(
      @Parameter(description = "Contains the answers to be verified.") @NotNull @Valid SecretQuestionsVerificationRequest request
   ) {
      Map<String, SecretQuestionsAnswer> answers = request.getAnswers()
         .entrySet()
         .stream()
         .collect(Collectors.toMap(Entry::getKey, e -> new SecretQuestionsAnswer(e.getValue())));
      FlowResult result = ((SecretQuestionsIdentityVerification)this.secretQuestionsCheck.get()).verifyQuestions(answers);
      return this.mapper.toResponse(result);
   }
}
