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

import com.airlock.iam.authentication.application.service.migration.MigrationSelection;
import com.airlock.iam.authentication.domain.model.migration.MigrationSelectionOptions;
import com.airlock.iam.authentication.infrastructure.generated.transfer.response.MigrationSelectionOptionsDataCollectionDocument;
import com.airlock.iam.authentication.infrastructure.transfer.response.MigrationSelectionOptionsData;
import com.airlock.iam.flow.api.domain.model.flow.FlowResult;
import com.airlock.iam.flow.api.domain.model.selection.Option;
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.infrastructure.mapper.FlowResultToCollectionDocumentMapper;
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.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.validation.constraints.Size;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
import ma.glasnost.orika.MapperFacade;

@Path("migration")
public final class MigrationResource {
   private static final String MIGRATION_OPTIONS_EXAMPLE = "{\n\t\"meta\": {\n\t\t\"type\": \"jsonapi.metadata.document\",\n\t\t\"timestamp\": \"2020-02-02T14:11:04.998+01:00\",\n\t\t\"migrationInfo\": {\n\t\t\t\"notAfter\": \"2020-02-06T09:00:00.000+01:00\",\n\t\t\t\"rejectPossible\": false,\n\t\t\t\"skipPossible\": true\n\t\t}\n\t},\n\t\"data\": [\n\t\t{\n\t\t\t\"type\": \"authentication.migration.option\",\n\t\t\t\"id\": \"CRONTO\",\n\t\t\t\"attributes\": {}\n\t\t},\n\t\t{\n\t\t\t\"type\": \"authentication.migration.option\",\n\t\t\t\"id\": \"MTAN\",\n\t\t\t\"attributes\": {}\n\t\t}\n\t]\n}\n";
   private final Provider<MigrationSelection> migration;
   private final FlowResultMapper mapper;
   private final MapperFacade mapperFacade;

   @Inject
   public MigrationResource(Provider<MigrationSelection> migration, FlowResultMapper mapper, MapperFacade mapperFacade) {
      this.migration = migration;
      this.mapper = mapper;
      this.mapperFacade = mapperFacade;
   }

   @ApiResponse(
      responseCode = "200",
      description = "Available migration selection options retrieved.",
      content = {
            @Content(
               mediaType = "application/vnd.api+json",
               schema = @Schema(implementation = MigrationSelectionOptionsDataCollectionDocument.class),
               examples = @ExampleObject(
                  name = "Migration options with meta data",
                  value = "{\n\t\"meta\": {\n\t\t\"type\": \"jsonapi.metadata.document\",\n\t\t\"timestamp\": \"2020-02-02T14:11:04.998+01:00\",\n\t\t\"migrationInfo\": {\n\t\t\t\"notAfter\": \"2020-02-06T09:00:00.000+01:00\",\n\t\t\t\"rejectPossible\": false,\n\t\t\t\"skipPossible\": true\n\t\t}\n\t},\n\t\"data\": [\n\t\t{\n\t\t\t\"type\": \"authentication.migration.option\",\n\t\t\t\"id\": \"CRONTO\",\n\t\t\t\"attributes\": {}\n\t\t},\n\t\t{\n\t\t\t\"type\": \"authentication.migration.option\",\n\t\t\t\"id\": \"MTAN\",\n\t\t\t\"attributes\": {}\n\t\t}\n\t]\n}\n"
               )
            ),
            @Content(
               mediaType = "application/json",
               schema = @Schema(implementation = MigrationSelectionOptionsDataCollectionDocument.class),
               examples = @ExampleObject(
                  name = "Migration options with meta data",
                  value = "{\n\t\"meta\": {\n\t\t\"type\": \"jsonapi.metadata.document\",\n\t\t\"timestamp\": \"2020-02-02T14:11:04.998+01:00\",\n\t\t\"migrationInfo\": {\n\t\t\t\"notAfter\": \"2020-02-06T09:00:00.000+01:00\",\n\t\t\t\"rejectPossible\": false,\n\t\t\t\"skipPossible\": true\n\t\t}\n\t},\n\t\"data\": [\n\t\t{\n\t\t\t\"type\": \"authentication.migration.option\",\n\t\t\t\"id\": \"CRONTO\",\n\t\t\t\"attributes\": {}\n\t\t},\n\t\t{\n\t\t\t\"type\": \"authentication.migration.option\",\n\t\t\t\"id\": \"MTAN\",\n\t\t\t\"attributes\": {}\n\t\t}\n\t]\n}\n"
               )
            )
      }
   )
   @Deprecated
   @Operation(
      description = "> [!caution]\n> This endpoint is deprecated. The migration options are returned as\n<a href=\"#additionalAuthAttributes\">additional attribute</a> with the <tt>MIGRATION_SELECTION_REQUIRED</tt> next step code.\n<p>Retrieves the available migration options the user can choose from to proceed in the migration process.\nThe metadata contains the migration information consisting of the migration date (if existing) and the\ninformation whether the user may skip (skipPossible) or reject (rejectPossible) the migration. See examples\nfor more details.</p>\n<div class=\"iam-resource-return\">The available migration options.</div>",
      tags = "Migration",
      summary = "List options"
   )
   @POST
   @Path("options/retrieve")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response retrieveOptions() {
      FlowResult result = ((MigrationSelection)this.migration.get()).retrieveOptions();
      return FlowResultToCollectionDocumentMapper.flowResultDataToCollectionDocumentMapper(this.mapper, this.mapperFacade)
         .map(result, MigrationSelectionOptions.class, MigrationSelectionOptionsData.class, option -> option);
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "Selected the chosen step and requires next step actions.",
               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 = "<div class=\"iam-error-code\"><table>\n<tr>\n<td>SELECTION_FAILED</td>\n<td>The selected option is not available.</td>\n</tr>\n</table>\n</div>\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 = "Selects the given migration option if available.\n<div class=\"iam-resource-return\">The selected next step or an error if the option is invalid.</div>",
      tags = "Migration",
      summary = "Select option"
   )
   @POST
   @Path("options/{id}/select")
   @Consumes("application/json")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response selectOption(@Parameter(description = "migration option to select.") @PathParam("id") @Size(min = 1, max = 1000) String id) {
      FlowResult result = ((MigrationSelection)this.migration.get()).select(Option.of(id));
      return this.mapper.toResponse(result);
   }

   @ApiResponse(
      responseCode = "200",
      description = "Skipped the migration.",
      content = {
            @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class)),
            @Content(mediaType = "application/json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class))
      }
   )
   @Operation(
      description = "Skips the migration for the moment. The user may migrate at a later time.\n<div class=\"iam-resource-return\">A success result if skipping the migration was successful.</div>",
      tags = "Migration",
      summary = "Skip migration"
   )
   @POST
   @Path("options/skip")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response skipMigration() {
      FlowResult result = ((MigrationSelection)this.migration.get()).skip();
      return this.mapper.toResponse(result);
   }

   @ApiResponse(
      responseCode = "200",
      description = "Rejected the migration.",
      content = {
            @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class)),
            @Content(mediaType = "application/json", schema = @Schema(implementation = AuthenticationFlowResultDataResourceDocument.class))
      }
   )
   @Operation(
      description = "Permanently rejects the migration. The user stays on their current authentication method.\n<div class=\"iam-resource-return\">A success result if rejecting the migration was successful.</div>",
      tags = "Migration",
      summary = "Reject migration"
   )
   @POST
   @Path("options/reject")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response rejectMigration() {
      FlowResult result = ((MigrationSelection)this.migration.get()).reject();
      return this.mapper.toResponse(result);
   }
}
