package binding

import (
	"net/http"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestBindingETagIsResourceScoped(t *testing.T) {
	require.Equal(t, `"workflow-binding:bnd_a:7"`, bindingETag("bnd_a", 7))
	revision, err := requireBindingRevision(bindingETag("bnd_a", 7), "bnd_a")
	require.NoError(t, err)
	require.Equal(t, int64(7), revision)

	_, err = requireBindingRevision(bindingETag("bnd_a", 7), "bnd_b")
	requireBindingHTTPError(t, err, http.StatusBadRequest, "binding_invalid_if_match")
}

func TestBindingMutationPreconditionsRejectAmbiguousETags(t *testing.T) {
	for _, test := range []struct {
		value  string
		status int
		code   string
	}{
		{value: "", status: http.StatusPreconditionRequired, code: "precondition_required"},
		{value: `W/"workflow-binding:bnd_a:1"`, status: http.StatusBadRequest, code: "binding_invalid_if_match"},
		{value: `"workflow-binding:bnd_a:1", "workflow-binding:bnd_a:2"`, status: http.StatusBadRequest, code: "binding_invalid_if_match"},
		{value: `"workflow-binding:bnd_a:0"`, status: http.StatusBadRequest, code: "binding_invalid_if_match"},
		{value: `"workflow-binding:bnd_a:nope"`, status: http.StatusBadRequest, code: "binding_invalid_if_match"},
	} {
		_, err := requireBindingRevision(test.value, "bnd_a")
		requireBindingHTTPError(t, err, test.status, test.code)
	}
}

func TestBindingIdempotencyKeyIsRequiredAndBounded(t *testing.T) {
	_, err := requireIdempotencyKey("")
	requireBindingHTTPError(t, err, http.StatusBadRequest, "binding_idempotency_key_required")
	_, err = requireIdempotencyKey(string(make([]byte, maxIdempotencyKeyLength+1)))
	requireBindingHTTPError(t, err, http.StatusBadRequest, "binding_invalid_idempotency_key")
	key, err := requireIdempotencyKey(" binding-call-1 ")
	require.NoError(t, err)
	require.Equal(t, "binding-call-1", key)
}

func requireBindingHTTPError(t *testing.T, err error, status int, code string) {
	t.Helper()
	response, ok := classifyError(err)
	require.True(t, ok)
	require.Equal(t, status, response.Status)
	require.Equal(t, code, response.Code)
	require.Equal(t, "binding", response.Stage)
}
