package binding

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

	"github.com/stretchr/testify/require"

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

type projectedBindingError struct {
	kind error
	code string
}

func TestClassifyManageBindingErrors(t *testing.T) {
	for _, test := range []struct {
		name    string
		kind    error
		code    bindingmanage.ErrorCode
		status  int
		details any
	}{
		{name: "validation failed", kind: storeerr.ErrUnprocessable, code: bindingmanage.ErrorCodeValidationFailed, status: http.StatusUnprocessableEntity, details: map[string]any{"x": 1}},
		{name: "revision conflict maps to 412", kind: storeerr.ErrConflict, code: bindingmanage.ErrorCodeRevisionConflict, status: http.StatusPreconditionFailed, details: map[string]any{"x": 1}},
		{name: "protected forbidden collapses to 404", kind: storeerr.ErrForbidden, code: bindingmanage.ErrorCodeForbidden, status: http.StatusNotFound},
	} {
		t.Run(test.name, func(t *testing.T) {
			response, ok := classifyError(bindingmanage.RequestError{Kind: test.kind, Code: test.code, Message: "failed", Details: map[string]any{"x": 1}})
			require.True(t, ok)
			require.Equal(t, test.status, response.Status)
			if test.details != nil {
				require.Equal(t, test.details, response.Details)
			} else {
				require.Nil(t, response.Details)
			}
		})
	}
}

func (err projectedBindingError) Error() string { return "binding failed" }
func (err projectedBindingError) Unwrap() error { return err.kind }
func (err projectedBindingError) BindingAPIError() (string, any) {
	return err.code, map[string]any{"expectedRevision": 1, "currentRevision": 2}
}

func TestClassifyBindingErrorPreservesRevisionDetails(t *testing.T) {
	response, ok := classifyError(projectedBindingError{kind: storeerr.ErrConflict, code: "binding_revision_conflict"})
	require.True(t, ok)
	require.Equal(t, http.StatusPreconditionFailed, response.Status)
	require.Equal(t, "binding_revision_conflict", response.Code)
	require.Equal(t, map[string]any{"expectedRevision": 1, "currentRevision": 2}, response.Details)
}

func TestClassifyBindingUnknownFailureFailsClosed(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("raw repository: dial tcp: SELECT secret FROM bindings"))
	require.True(t, ok)
	require.Equal(t, http.StatusInternalServerError, response.Status)
	require.Equal(t, "binding_request_failed", response.Code)
	require.NotContains(t, response.Message, "dial tcp")
	require.NotContains(t, response.Message, "secret")
	require.Nil(t, response.Details)
}
