package com.hubspot.singularity.resources;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Inject;
import com.hubspot.singularity.SingularityAuthorizationScope;
import com.hubspot.singularity.SingularityRequestWithState;
import com.hubspot.singularity.SingularityUser;
import com.hubspot.singularity.WebExceptions;
import com.hubspot.singularity.auth.SingularityAuthorizationHelper;
import com.hubspot.singularity.config.ApiPaths;
import com.hubspot.singularity.data.RequestManager;
import com.hubspot.singularity.data.ShuffleConfigurationManager;
import com.ning.http.client.AsyncHttpClient;
import io.dropwizard.auth.Auth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.tags.Tags;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.List;
import java.util.Optional;

@Path(ApiPaths.SHUFFLE_RESOURCE_PATH)
@Produces({ MediaType.APPLICATION_JSON })
@Schema(title = "Manages shuffle configuration of Singularity.")
@Tags({@Tag(name = "Shuffle")})
public class ShuffleConfigurationResource extends AbstractLeaderAwareResource {
  private static final Logger LOG = LoggerFactory.getLogger(ShuffleConfigurationResource.class);

  private final ShuffleConfigurationManager shuffleCfgManager;
  private final SingularityAuthorizationHelper authorizationHelper;
  private final RequestManager requestManager;

  @Inject
  public ShuffleConfigurationResource(
      AsyncHttpClient httpClient, LeaderLatch leaderLatch, ObjectMapper objectMapper,
      ShuffleConfigurationManager shuffleCfgManager,
      SingularityAuthorizationHelper authorizationHelper,
      RequestManager requestManager
  ) {
    super(httpClient, leaderLatch, objectMapper);

    this.shuffleCfgManager = shuffleCfgManager;
    this.authorizationHelper = authorizationHelper;
    this.requestManager = requestManager;
  }

  private void checkReadAuthorization(SingularityUser user, String requestId) {
    checkRequestAuthorization(user, requestId, SingularityAuthorizationScope.READ);
  }

  private void checkWriteAuthorization(SingularityUser user, String requestId) {
    checkRequestAuthorization(user, requestId, SingularityAuthorizationScope.WRITE);
  }

  private void checkRequestAuthorization(SingularityUser user, String requestId, SingularityAuthorizationScope scope) {
    Optional<SingularityRequestWithState> request = requestManager.getRequest(requestId);

    if (request.isPresent()) {
      authorizationHelper.checkForAuthorization(request.get().getRequest(), user, scope);
    }
  }

  @GET
  @Path("/blacklist")
  @Operation(summary = "Retrieve the set of request IDs that should not be shuffled.")
  public List<String> getShuffleBlacklist(@Parameter(hidden = true) @Auth SingularityUser user) {
    authorizationHelper.checkReadAuthorization(user);
    return shuffleCfgManager.getShuffleBlacklist();
  }

  @GET
  @Path("/blacklist/{requestId}")
  @Operation(summary = "Check if a request ID is on the shuffle blacklist.")
  public boolean isOnShuffleBlacklist(
      @Parameter(hidden = true) @Auth SingularityUser user,
      @Parameter(required = true, description = "The Request ID to fetch crash loops for") @PathParam("requestId") String requestId
  ) {
    checkReadAuthorization(user, requestId);
    return shuffleCfgManager.isOnShuffleBlacklist(requestId);
  }

  @POST
  @Path("/blacklist/{requestId}")
  @Operation(summary = "Add a request ID to the shuffle blacklist. No effect if already present.")
  public void addToShuffleBlacklist(
      @Parameter(hidden = true) @Auth SingularityUser user,
      @Parameter(required = true, description = "The Request ID to fetch crash loops for") @PathParam("requestId") String requestId
  ) {
    checkWriteAuthorization(user, requestId);
    shuffleCfgManager.addToShuffleBlacklist(requestId);
  }

  @DELETE
  @Path("/blacklist/{requestId}")
  @Operation(summary = "Remove a request ID from the shuffle blacklist. No effect if not present.")
  public void removeFromShuffleBlacklist(
      @Parameter(hidden = true) @Auth SingularityUser user,
      @Parameter(required = true, description = "The Request ID to fetch crash loops for") @PathParam("requestId") String requestId
  ) {
    checkWriteAuthorization(user, requestId);
    shuffleCfgManager.removeFromShuffleBlacklist(requestId);
  }
}

@@ -1747,55 +1747,8 @@
 per;
-%0A  private final RequestManager requestManager;
 %0A%0A  
@@ -1993,45 +1993,8 @@
 lper
-,%0A      RequestManager requestManager
 %0A  )
@@ -2151,733 +2151,8 @@
 er;%0A
-    this.requestManager = requestManager;%0A  %7D%0A%0A  private void checkReadAuthorization(SingularityUser user, String requestId) %7B%0A    checkRequestAuthorization(user, requestId, SingularityAuthorizationScope.READ);%0A  %7D%0A%0A  private void checkWriteAuthorization(SingularityUser user, String requestId) %7B%0A    checkRequestAuthorization(user, requestId, SingularityAuthorizationScope.WRITE);%0A  %7D%0A%0A  private void checkRequestAuthorization(SingularityUser user, String requestId, SingularityAuthorizationScope scope) %7B%0A    Optional%3CSingularityRequestWithState%3E request = requestManager.getRequest(requestId);%0A%0A    if (request.isPresent()) %7B%0A      authorizationHelper.checkForAuthorization(request.get().getRequest(), user, scope);%0A    %7D%0A
   %7D%0A
@@ -2836,25 +2836,44 @@
 ) %7B%0A    
+authorizationHelper.
 check
-Read
+For
 Authoriz
@@ -2877,32 +2877,79 @@
 rization
-(user, requestId
+ByRequestId(requestId, user, SingularityAuthorizationScope.READ
 );%0A    r
@@ -3394,47 +3394,113 @@
     
-checkWriteAuthorization(user, requestId
+authorizationHelper.checkForAuthorizationByRequestId(requestId, user, SingularityAuthorizationScope.WRITE
 );%0A 
@@ -3951,47 +3951,113 @@
     
-checkWriteAuthorization(user, requestId
+authorizationHelper.checkForAuthorizationByRequestId(requestId, user, SingularityAuthorizationScope.WRITE
 );%0A 

improve shuffle resource authorization