package binding

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/api/dto"
)

func TestWorkflowBindingJSONIsStrictAndBounded(t *testing.T) {
	gin.SetMode(gin.TestMode)
	for _, test := range []struct {
		name   string
		body   string
		status int
		code   string
	}{
		{name: "valid", body: `{"planId":"pln_1","planVersionId":"plv_1","source":{"type":"schedule","schedule":{"mode":"relative","relativeSeconds":60,"inputs":{}}}}`, status: 0},
		{name: "identity cannot be supplied", body: `{"planVersionId":"plv_1","source":{},"owner":{"userId":"usr_x"}}`, status: http.StatusBadRequest, code: "binding_invalid_json"},
		{name: "workspace cannot be supplied", body: `{"planVersionId":"plv_1","source":{},"workspaceId":"wsp_x"}`, status: http.StatusBadRequest, code: "binding_invalid_json"},
		{name: "unknown typo", body: `{"planVersionID":"plv_1","source":{}}`, status: http.StatusBadRequest, code: "binding_invalid_json"},
		{name: "duplicate key", body: `{"planVersionId":"a","planVersionId":"b","source":{}}`, status: http.StatusBadRequest, code: "binding_invalid_json"},
		{name: "multiple values", body: `{"planVersionId":"a","source":{}} {}`, status: http.StatusBadRequest, code: "binding_invalid_json"},
		{name: "object required", body: `null`, status: http.StatusBadRequest, code: "binding_invalid_json"},
		{name: "oversized", body: `{"planVersionId":"p","source":{"x":"` + strings.Repeat("x", int(maxWorkflowBindingRequestBytes)) + `"}}`, status: http.StatusRequestEntityTooLarge, code: "binding_request_too_large"},
	} {
		t.Run(test.name, func(t *testing.T) {
			recorder := httptest.NewRecorder()
			ctx, _ := gin.CreateTestContext(recorder)
			ctx.Request = httptest.NewRequest(http.MethodPost, "/", strings.NewReader(test.body))
			_, err := decodeWorkflowBindingJSON[dto.WorkflowBindingValidateRequest](ctx)
			if test.status == 0 {
				require.NoError(t, err)
				return
			}
			requireBindingHTTPError(t, err, test.status, test.code)
		})
	}
}

func TestWorkflowBindingJSONRejectsExcessiveNesting(t *testing.T) {
	payload := `{"planVersionId":"p","source":` + strings.Repeat("[", maxWorkflowBindingJSONNesting+1) + strings.Repeat("]", maxWorkflowBindingJSONNesting+1) + `}`
	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())
	ctx.Request = httptest.NewRequest(http.MethodPost, "/", strings.NewReader(payload))
	_, err := decodeWorkflowBindingJSON[dto.WorkflowBindingValidateRequest](ctx)
	requireBindingHTTPError(t, err, http.StatusBadRequest, "binding_invalid_json")
}
