package plan

import (
	"net/http"
	"testing"

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

func TestPlanAndDraftETagsDoNotCrossResourceBoundaries(t *testing.T) {
	require.Equal(t, `"workflow-plan:pln_a:7"`, planETag("pln_a", 7))
	require.Equal(t, `"workflow-plan-draft:pln_a:9"`, draftETag("pln_a", 9))

	planRevision, err := requirePlanRevision(planETag("pln_a", 7), "pln_a")
	require.NoError(t, err)
	require.Equal(t, int64(7), planRevision)

	draftRevision, err := requireDraftRevision(draftETag("pln_a", 9), "pln_a")
	require.NoError(t, err)
	require.Equal(t, int64(9), draftRevision)

	_, err = requirePlanRevision(draftETag("pln_a", 9), "pln_a")
	requirePlanHTTPError(t, err, http.StatusBadRequest, "invalid_if_match")

	_, err = requirePlanRevision(planETag("pln_a", 7), "pln_b")
	requirePlanHTTPError(t, err, http.StatusBadRequest, "invalid_if_match")
}

func TestRequireRevisionRejectsMissingWeakMultipleAndInvalidETags(t *testing.T) {
	tests := []struct {
		value  string
		status int
		code   string
	}{
		{value: "", status: http.StatusPreconditionRequired, code: "precondition_required"},
		{value: `W/"workflow-plan:pln_a:1"`, status: http.StatusBadRequest, code: "invalid_if_match"},
		{value: `"workflow-plan:pln_a:1", "workflow-plan:pln_a:2"`, status: http.StatusBadRequest, code: "invalid_if_match"},
		{value: `"workflow-plan:pln_a:0"`, status: http.StatusBadRequest, code: "invalid_if_match"},
		{value: `"workflow-plan:pln_a:nope"`, status: http.StatusBadRequest, code: "invalid_if_match"},
	}
	for _, test := range tests {
		_, err := requirePlanRevision(test.value, "pln_a")
		requirePlanHTTPError(t, err, test.status, test.code)
	}
}

// requirePlanHTTPError projects a precondition failure through the canonical
// public classifier and asserts the stable status/code of the public contract.
func requirePlanHTTPError(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, "plan", response.Stage)
}
