package com.atlassian.bitbucket.mesh.throttle;

import com.atlassian.bitbucket.mesh.AbstractStatusException;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcError;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcErrorUtils;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcResourceBusy;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcThrottledResource;
import io.grpc.Metadata;
import io.grpc.Status;

import javax.annotation.Nonnull;

import static java.util.Objects.requireNonNull;

/**
 * Thrown to indicate a resource is busy.
 *
 * @see ThrottleService#acquireTicket(ThrottledResource)
 */
public class ResourceBusyException extends AbstractStatusException {

    private final ThrottledResource resource;
    
    public ResourceBusyException(String message, @Nonnull ThrottledResource resource) {
        super(message, Status.RESOURCE_EXHAUSTED);

        this.resource = requireNonNull(resource, "resource");
    }

    /**
     * @return the busy resource
     */
    @Nonnull
    public ThrottledResource getResource() {
        return resource;
    }

    @Override
    protected Metadata getTrailers() {
        return RpcErrorUtils.toMetadata(RpcError.newBuilder()
                .setResourceBusy(RpcResourceBusy.newBuilder()
                    .setResource(asThrottledResource(resource)))
                .build());
    }

    private static RpcThrottledResource asThrottledResource(ThrottledResource resource) {
        switch (resource) {
            case COMMAND:
                return RpcThrottledResource.RESOURCE_COMMAND;
            case MIRROR_PACK:
                return RpcThrottledResource.RESOURCE_MIRROR_PACK;
            case LFS:
                return RpcThrottledResource.RESOURCE_LFS;
            case PACK:
                return RpcThrottledResource.RESOURCE_PACK;
            case REFS:
                return RpcThrottledResource.RESOURCE_REFS;
            default:
                return RpcThrottledResource.RESOURCE_UNSPECIFIED;
        }
    }
}
