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

import ch.ergon.restal.jsonapi.document.data.CollectionDocument;
import com.airlock.iam.admin.application.service.accountlink.AccountLinkService;
import com.airlock.iam.admin.infrastructure.generated.transfer.response.user.UserAccountLinkDataCollectionDocument;
import com.airlock.iam.admin.infrastructure.service.user.UserIdResolver;
import com.airlock.iam.admin.infrastructure.transfer.response.user.UserAccountLinkData;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.base.infrastructure.error.ErrorResponse;
import com.airlock.iam.base.infrastructure.mapper.entity.RestMapper;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.domain.model.accountlink.AccountLinkId;
import com.airlock.iam.common.domain.model.accountlink.persistence.AccountLinkData;
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.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 java.util.Collection;
import java.util.Optional;

@Path("/users/{userId}/account-links")
public class UserAccountLinkResource {
   private final Provider<AccountLinkService> accountLinkService;
   private final RestMapper mapper;
   private final Provider<UserIdResolver> userIdResolver;

   @Inject
   public UserAccountLinkResource(Provider<AccountLinkService> accountLinkService, RestMapper mapper, Provider<UserIdResolver> userIdResolver) {
      this.accountLinkService = accountLinkService;
      this.mapper = mapper;
      this.userIdResolver = userIdResolver;
   }

   @ApiResponses(
      {
            @ApiResponse(
               responseCode = "200",
               description = "Retrieved account links.",
               content = {
                     @Content(mediaType = "application/vnd.api+json", schema = @Schema(implementation = UserAccountLinkDataCollectionDocument.class)),
                     @Content(mediaType = "application/json", schema = @Schema(implementation = UserAccountLinkDataCollectionDocument.class))
               }
            ),
            @ApiResponse(
               responseCode = "404",
               description = "The user 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(
      description = "Retrieves account links of the user.\n<div class=\"iam-resource-return\">All account links of the user.</div>",
      tags = "OAuth 2.0/OIDC",
      summary = "List account links"
   )
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response listAccountLinks(@PathParam("userId") @Parameter(schema = @Schema(type = "string")) String userIdParam) {
      UserId userId = ((UserIdResolver)this.userIdResolver.get()).resolve(userIdParam);
      Collection<AccountLinkData> accountLinks = ((AccountLinkService)this.accountLinkService.get()).accountLinks(userId);
      CollectionDocument<UserAccountLinkData> document = this.mapper
         .forElements(accountLinks, UserAccountLinkData.class)
         .withIdSupplier(AccountLinkData::getProviderId)
         .toCollection();
      return Response.ok().entity(document).build();
   }

   @ApiResponses(
      {
            @ApiResponse(responseCode = "204", description = "The account link was removed."),
            @ApiResponse(
               responseCode = "404",
               description = "The user or account link was not found.",
               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"))
               }
            )
      }
   )
   @Path("/{id}")
   @Operation(
      description = "Removes the account link identified by the provider ID.\n<div class=\"iam-resource-return\">Whether the operation was successful.</div>",
      tags = "OAuth 2.0/OIDC",
      summary = "Remove account link"
   )
   @DELETE
   @Produces({"application/vnd.api+json", "application/json;qs=0.9"})
   public Response remove(
      @PathParam("userId") @Parameter(schema = @Schema(type = "string")) String userIdParam,
      @Parameter(description = "The provider ID of the account link to be removed.") @PathParam("id") String providerId
   ) {
      UserId userId = ((UserIdResolver)this.userIdResolver.get()).resolve(userIdParam);
      Optional<AccountLinkData> link = ((AccountLinkService)this.accountLinkService.get()).findLink(userId, providerId);
      if (link.isEmpty()) {
         return this.noAccountLinkFound(userId.getValue());
      }

      ((AccountLinkService)this.accountLinkService.get()).unlink(AccountLinkId.accountLinkId(link.get().getId()));
      return Response.noContent().build();
   }

   private Response noAccountLinkFound(String userId) {
      return ErrorResponse.notFound().log(String.format("User %s does not have an account link.", LogUtil.quote(userId))).build().toResponse();
   }
}
