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

import ch.ergon.restal.jsonapi.document.data.ResourceDocument;
import ch.ergon.restal.jsonapi.document.data.ResourceObject;
import com.airlock.iam.admin.application.service.user.rememberme.RememberMeManagementService;
import com.airlock.iam.admin.infrastructure.generated.transfer.response.RememberMeDataResourceDocument;
import com.airlock.iam.admin.infrastructure.service.user.UserIdResolver;
import com.airlock.iam.base.api.domain.model.exception.ServiceConfigurationException;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.base.infrastructure.error.ErrorResponse;
import com.airlock.iam.common.infrastructure.exception.IamRestErrorCode;
import com.airlock.iam.log.api.helpdesk.HelpdeskLogger;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
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.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import java.util.Optional;

@Path("/users/{userId}/tokens/remember-me")
public class UserRememberMeResource {
   private final Provider<Optional<RememberMeManagementService>> management;
   private final HelpdeskLogger helpdeskLogger;
   private final Provider<UserIdResolver> userIdResolver;

   @Inject
   public UserRememberMeResource(
      Provider<Optional<RememberMeManagementService>> management, HelpdeskLogger helpdeskLogger, Provider<UserIdResolver> userIdResolver
   ) {
      this.management = management;
      this.helpdeskLogger = helpdeskLogger;
      this.userIdResolver = userIdResolver;
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "The user has remember-me cookies.",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = RememberMeDataResourceDocument.class)),
                     @Content(mediaType = "application/json", schema = @Schema(implementation = RememberMeDataResourceDocument.class))
               }
            ),
            @ApiResponse(
               responseCode = "404",
               description = "The user does not exist or does not have remember-me cookies.",
               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
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   @Operation(
      description = "Retrieves information about the user's remember-me cookies.\n<div class=\"iam-resource-return\">Information about the remember-me cookies.</div>",
      extensions = @Extension(properties = @ExtensionProperty(name = "x-internal", value = "true")),
      tags = "Remember-Me",
      summary = "Get cookies info"
   )
   public Response rememberMeSecrets(@PathParam("userId") @Parameter(schema = @Schema(type = "string")) String userIdParam) {
      UserId userId = ((UserIdResolver)this.userIdResolver.get()).resolve(userIdParam);
      return this.management().hasAnyRememberMeTokens(userId)
         ? Response.status(Status.OK).entity(this.rememberMeResourceDocument(userId)).build()
         : ErrorResponse.notFound().build().toResponse();
   }

   @ApiResponses(
      {
            @ApiResponse(responseCode = "204", description = "The cookies have been invalidated successfully."),
            @ApiResponse(
               responseCode = "404",
               description = "<div class=\"iam-error-code\"><table>\n<tr>\n<td>ITEM_NOT_FOUND</td>\n<td>The user does not have any remember-me cookies.</td>\n</tr>\n<tr>\n<td>USER_NOT_FOUND</td>\n<td>The user does not exist.</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"))
               }
            )
      }
   )
   @DELETE
   @Operation(
      tags = "Remember-Me",
      description = "Invalidates the remember-me cookies for a specific user.\n<div class=\"iam-resource-return\">Information about whether the remember-me cookies have been invalidated successfully.</div>",
      summary = "Invalidate cookies"
   )
   @Consumes("application/json")
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response deleteRememberMeCookies(@PathParam("userId") @Parameter(schema = @Schema(type = "string")) String userIdParam) {
      UserId userId = ((UserIdResolver)this.userIdResolver.get()).resolve(userIdParam);
      if (!this.management().hasAnyRememberMeTokens(userId)) {
         this.helpdeskLogger
            .log(
               userId,
               "Administrator ${authentee} tried to invalidate the Remember-Me cookies for user ${affectedUser}, but the user does not have any cookies."
            );
         return ErrorResponse.notFound().errorCode(IamRestErrorCode.ITEM_NOT_FOUND).build().toResponse();
      } else {
         this.management().deleteAllRememberMeTokensOf(userId);
         return Response.noContent().build();
      }
   }

   private ResourceDocument<Void> rememberMeResourceDocument(UserId transformedUserId) {
      return ResourceObject.builder("user.token.remember-me", transformedUserId.getValue()).document();
   }

   private RememberMeManagementService management() {
      return (RememberMeManagementService)ServiceConfigurationException.checkPresent((Optional)this.management.get(), "Remember-Me feature is not configured!");
   }
}
