package runmanage

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/require"

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

// TestMapRepositoryErrorNeverTrustsRepositoryProse proves every repository
// BadRequest/Conflict and adjacent selector maps to reviewed stable problem
// text. A secret marker embedded in the repository error never reaches the
// RequestError message, the stable domain code is preserved, and the original
// repository error remains reachable only through the separate InternalCause
// accessor (logs/wrapping), never through the public message or the errors.Is
// classification graph.
func TestMapRepositoryErrorNeverTrustsRepositoryProse(t *testing.T) {
	const secret = "REPO-SECRET-8e17c3a4"
	tests := []struct {
		name     string
		err      error
		wantCode ErrorCode
	}{
		{
			name: "generic bad request", err: storeerr.BadRequest("repository rejected input: " + secret),
			wantCode: ErrorCodeInvalidRequest,
		},
		{
			name: "generic conflict", err: storeerr.Conflict("repository CAS conflict: " + secret),
			wantCode: ErrorCodeConflict,
		},
		{
			name: "forbidden selector", err: storeerr.Forbidden("repository denied access: " + secret),
			wantCode: ErrorCodeForbidden,
		},
		{
			name: "not found selector", err: storeerr.NotFound("missing Workflow Run " + secret),
			wantCode: ErrorCodeNotFound,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			mapped := mapRepositoryError(test.err)
			require.NotNil(t, mapped)
			require.NotContains(t, mapped.Error(), secret, "repository prose must never become the public message")
			code, _, ok := ErrorDetails(mapped)
			require.True(t, ok)
			require.Equal(t, test.wantCode, code)
			// The internal cause is retained only for logs/wrapping through the
			// separate accessor; it must not participate in the errors.Is graph.
			cause := storeerr.InternalCause(mapped)
			require.NotNil(t, cause, "mapped error must preserve the repository cause for logging")
			require.True(t, errors.Is(cause, test.err), "preserved cause must wrap the repository error")
		})
	}
}

// TestRequestErrorKindAuthoritativeAcrossMixedSentinels proves the declared
// manage RequestError Kind stays authoritative for public status/code even when
// the preserved Cause wraps a DIFFERENT store sentinel: a conflict RequestError
// whose internal cause is a bad-request or not-found must never be classified as
// 400/404 through errors.Is. The cause remains reachable only through the
// InternalCause accessor.
func TestRequestErrorKindAuthoritativeAcrossMixedSentinels(t *testing.T) {
	tests := []struct {
		name      string
		kind      error
		code      ErrorCode
		cause     error
		wantOther error
	}{
		{
			name: "conflict wraps bad request", kind: storeerr.ErrConflict, code: ErrorCodeConflict,
			cause: storeerr.BadRequest("internal repository bad request"), wantOther: storeerr.ErrBadRequest,
		},
		{
			name: "conflict wraps not found", kind: storeerr.ErrConflict, code: ErrorCodeConflict,
			cause: storeerr.NotFound("internal repository not found"), wantOther: storeerr.ErrNotFound,
		},
		{
			name: "not found wraps bad request", kind: storeerr.ErrNotFound, code: ErrorCodeNotFound,
			cause: storeerr.BadRequest("internal repository bad request"), wantOther: storeerr.ErrBadRequest,
		},
		{
			name: "forbidden wraps not found", kind: storeerr.ErrForbidden, code: ErrorCodeForbidden,
			cause: storeerr.NotFound("internal repository not found"), wantOther: storeerr.ErrNotFound,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			err := RequestError{Kind: test.kind, Code: test.code, Message: "Workflow Run request failed", Cause: test.cause}
			require.True(t, errors.Is(err, test.kind), "declared kind must match")
			require.False(t, errors.Is(err, test.wantOther), "internal cause sentinel must not participate in errors.Is")
			require.NotNil(t, storeerr.InternalCause(err))
			require.True(t, errors.Is(storeerr.InternalCause(err), test.wantOther), "InternalCause must retain the internal cause")
			code, _, ok := ErrorDetails(err)
			require.True(t, ok)
			require.Equal(t, test.code, code)
		})
	}
}
