package invocation

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
	"github.com/tidbcloud/AgentTeam/internal/workflow/invocationmanage"
)

func TestClassifyInvocationManageErrors(t *testing.T) {
	for _, test := range []struct {
		kind   error
		code   invocationmanage.ErrorCode
		status int
	}{
		{kind: storeerr.ErrBadRequest, code: invocationmanage.ErrorCodeInvalidRequest, status: http.StatusBadRequest},
		{kind: storeerr.ErrForbidden, code: invocationmanage.ErrorCodePrincipalUnavailable, status: http.StatusForbidden},
		{kind: storeerr.ErrNotFound, code: invocationmanage.ErrorCodeNotFound, status: http.StatusNotFound},
		{kind: storeerr.ErrConflict, code: invocationmanage.ErrorCodePlanVersionUnavailable, status: http.StatusConflict},
		{kind: storeerr.ErrUnprocessable, code: invocationmanage.ErrorCodeInputInvalid, status: http.StatusUnprocessableEntity},
	} {
		response, ok := classifyError(invocationmanage.RequestError{
			Kind: test.kind, Code: test.code, Message: "failed", Details: map[string]any{"field": "input"},
		})
		require.True(t, ok)
		require.Equal(t, test.status, response.Status)
		require.Equal(t, string(test.code), response.Code)
		// 404/403 responses are non-enumerating: structured details are never
		// projected for not-found or forbidden failures.
		if test.status == http.StatusForbidden || test.status == http.StatusNotFound {
			require.Nil(t, response.Details)
		} else {
			require.Equal(t, map[string]any{"field": "input"}, response.Details)
		}
	}
}

func TestClassifyInvocationUnknownFailureFailsClosed(t *testing.T) {
	// Unknown failures must fail closed: the classifier returns a bounded
	// generic internal error rather than leaking the raw error text.
	response, ok := classifyError(fmt.Errorf("dial tcp: connection refused: raw sql: SELECT secret FROM ..."))
	require.True(t, ok)
	require.Equal(t, http.StatusInternalServerError, response.Status)
	require.Equal(t, "invocation_request_failed", response.Code)
	require.NotContains(t, response.Message, "dial tcp")
	require.NotContains(t, response.Message, "secret")
	require.Nil(t, response.Details)
}
