package com.airlock.iam.admin.infrastructure.resource.prot;

import ch.ergon.restal.jsonapi.document.data.ResourceDocument;
import ch.ergon.restal.jsonapi.document.data.ResourceObject;
import ch.ergon.restal.jsonapi.document.request.RequestDocument;
import com.airlock.iam.admin.application.service.maintenancemessage.MaintenanceMessageService;
import com.airlock.iam.admin.domain.model.maintenancemessage.MaintenanceMessage;
import com.airlock.iam.admin.infrastructure.generated.transfer.response.MaintenanceMessageDataResourceDocument;
import com.airlock.iam.admin.infrastructure.transfer.request.MaintenanceMessagePatchRequest;
import com.airlock.iam.admin.infrastructure.transfer.response.MaintenanceMessageData;
import com.airlock.iam.base.api.domain.model.validation.ValidationResult;
import com.airlock.iam.base.api.infrastructure.uri.ExternalUriInfo;
import com.airlock.iam.base.infrastructure.error.ErrorResponse;
import com.airlock.iam.base.infrastructure.mapper.ValidationToErrorMapper;
import com.airlock.iam.base.infrastructure.mapper.jsonapi.JsonApiErrorSourcePointerMapper;
import com.airlock.iam.common.application.exception.RequestDocumentAttributesMissingException;
import com.airlock.iam.common.infrastructure.resource.Resources;
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.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
import java.util.Optional;
import ma.glasnost.orika.MapperFacade;

@Path("/maintenance-messages/{messageId}")
public class MaintenanceMessageResource {
   static final JsonApiErrorSourcePointerMapper MAINTENANCE_MESSAGE_SOURCE_POINTER_MAPPER = JsonApiErrorSourcePointerMapper.builder().idField("name").build();
   protected static final String MESSAGE_ID = "messageId";
   private final Provider<Optional<MaintenanceMessageService>> maintenanceMessageService;
   private final MapperFacade mapper;
   private final Provider<ExternalUriInfo> uriInfo;
   private final ValidationToErrorMapper errorMapper;

   @Inject
   public MaintenanceMessageResource(
      Provider<Optional<MaintenanceMessageService>> maintenanceMessageService,
      MapperFacade mapper,
      Provider<ExternalUriInfo> uriInfo,
      ValidationToErrorMapper errorMapper
   ) {
      this.maintenanceMessageService = maintenanceMessageService;
      this.mapper = mapper;
      this.uriInfo = uriInfo;
      this.errorMapper = errorMapper;
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "Requested message found.",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = MaintenanceMessageDataResourceDocument.class)),
                     @Content(mediaType = "application/json", schema = @Schema(implementation = MaintenanceMessageDataResourceDocument.class))
               }
            ),
            @ApiResponse(
               responseCode = "404",
               description = "The message does not exist.",
               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"))
               }
            )
      }
   )
   @GET
   @Operation(
      tags = "Maintenance Messages",
      description = "Retrieves a specific maintenance message.\n<div class=\"iam-resource-return\">The available information about the message.</div>",
      summary = "Get maintenance message"
   )
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response retrieve(@Parameter(description = "The identification of the message.") @PathParam("messageId") String messageId) {
      if (((Optional)this.maintenanceMessageService.get()).isEmpty()) {
         return ErrorResponse.notImplemented().build().toResponse();
      }

      Optional<MaintenanceMessage> message = ((MaintenanceMessageService)((Optional)this.maintenanceMessageService.get()).orElseThrow()).find(messageId);
      return message.isEmpty() ? ErrorResponse.notFound().build().toResponse() : this.toResponse(message.get());
   }

   @ApiResponses(
      {
            @ApiResponse(responseCode = "204", description = "The message has been deleted."),
            @ApiResponse(
               responseCode = "404",
               description = "The message does not exist.",
               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"))
               }
            )
      }
   )
   @DELETE
   @Operation(
      tags = "Maintenance Messages",
      description = "Deletes an existing maintenance message.\n<div class=\"iam-resource-return\">A Response indicating whether the message was successfully deleted or not.</div>",
      summary = "Delete maintenance message"
   )
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response delete(@Parameter(description = "The identification of the message.") @PathParam("messageId") String messageId) {
      if (((Optional)this.maintenanceMessageService.get()).isEmpty()) {
         return ErrorResponse.notImplemented().build().toResponse();
      }

      if (((MaintenanceMessageService)((Optional)this.maintenanceMessageService.get()).orElseThrow()).find(messageId).isEmpty()) {
         return ErrorResponse.notFound().build().toResponse();
      }

      ((MaintenanceMessageService)((Optional)this.maintenanceMessageService.get()).orElseThrow()).delete(messageId);
      return Response.noContent().build();
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "The maintenance message was updated successfully. The complete updated message is returned.",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = MaintenanceMessageDataResourceDocument.class)),
                     @Content(mediaType = "application/json", schema = @Schema(implementation = MaintenanceMessageDataResourceDocument.class))
               }
            ),
            @ApiResponse(
               responseCode = "404",
               description = "The requested maintenance message does not exist.",
               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"))
               }
            )
      }
   )
   @PATCH
   @Operation(
      tags = "Maintenance Messages",
      description = "Updates a maintenance message.\nTo delete a translation for a given language, explicitly set that translation to <tt>null</tt>.\n<div class=\"iam-resource-return\">The updated maintenance message or an error document.</div>",
      summary = "Update maintenance message"
   )
   @Consumes({"application/vnd.api+json", "application/json"})
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response update(
      @Parameter(description = "The identification of the message.") @PathParam("messageId") String messageId,
      @Parameter(description = "The document containing the attributes that should be updated. Omitted attributes are left unchanged.") @NotNull @Valid RequestDocument<MaintenanceMessagePatchRequest> request
   ) {
      if (!messageId.equals(request.getData().getId())) {
         return ErrorResponse.badRequest().log("Inconsistent id in URL and body.").build().toResponse();
      }

      MaintenanceMessagePatchRequest attributes = (MaintenanceMessagePatchRequest)RequestDocumentAttributesMissingException.checkAttributesPresent(request);
      if (((Optional)this.maintenanceMessageService.get()).isEmpty()) {
         return ErrorResponse.notImplemented().build().toResponse();
      }

      if (((MaintenanceMessageService)((Optional)this.maintenanceMessageService.get()).orElseThrow()).find(messageId).isEmpty()) {
         return ErrorResponse.notFound().build().toResponse();
      }

      MaintenanceMessageService.MaintenanceMessageUpdateParams params = MaintenanceMessageService.MaintenanceMessageUpdateParams.builder()
         .mmId(request.getData().getId())
         .active(attributes.getActive())
         .location(attributes.getLocation())
         .systemAvailable(attributes.getSystemAvailable())
         .validFrom(attributes.getValidFrom())
         .validTo(attributes.getValidTo())
         .translations(attributes.getTranslations())
         .build();
      ValidationResult validationResult = ((MaintenanceMessageService)((Optional)this.maintenanceMessageService.get()).orElseThrow()).validate(params);
      if (!validationResult.isValid()) {
         return this.errorMapper.withFieldToSourcePointerMapper(MAINTENANCE_MESSAGE_SOURCE_POINTER_MAPPER).mapToResponse(validationResult.getErrors());
      }

      MaintenanceMessage newMm = ((MaintenanceMessageService)((Optional)this.maintenanceMessageService.get()).orElseThrow()).update(params);
      return this.toResponse(newMm);
   }

   private Response toResponse(MaintenanceMessage mm) {
      MaintenanceMessageData to = (MaintenanceMessageData)this.mapper.map(mm, MaintenanceMessageData.class);
      ResourceDocument<MaintenanceMessageData> document = ResourceObject.builder(mm.getName(), to)
         .linkSelf(Resources.link((ExternalUriInfo)this.uriInfo.get(), MaintenanceMessageResource.class).build(new Object[]{mm.getName()}).getUri())
         .document();
      return Response.ok().entity(document).build();
   }
}
