package memory

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/api/meshxapi"
	"github.com/tidbcloud/AgentTeam/internal/identity/trusted"
	"github.com/tidbcloud/AgentTeam/internal/service/resource/repos"
	reposstore "github.com/tidbcloud/AgentTeam/internal/store/resource/repos"
)

func TestCreateMemoryPreservesRepositoryErrorResponses(t *testing.T) {
	alreadyExists := repos.RepositoryAlreadyExistsConflict(
		"usr_1/runbooks.mem",
		reposstore.ResourceTypeMemory,
		"mem_1",
		reposstore.RepoRolePrimary,
		repos.RepositoryNameFieldName,
		"runbooks-2",
	)
	_, _, reservedSuffix := repos.ResolveRepositoryNameStem("Runbooks", "runbooks.mem", "memory", ".mem", "memory")
	_, _, invalidOverride := repos.ResolveRepositoryNameStem("Runbooks", "!!!", "memory", ".mem", "memory")
	tests := []struct {
		name    string
		err     error
		status  int
		code    string
		message string
		details repos.RepositoryNameConflictDetails
	}{
		{
			name:    "already exists",
			err:     alreadyExists,
			status:  http.StatusConflict,
			code:    repos.RepositoryAlreadyExistsCode,
			message: "repository usr_1/runbooks.mem already exists",
			details: repos.RepositoryNameConflictDetails{
				ConflictOwner:     "usr_1",
				ConflictRepo:      "runbooks.mem",
				ResourceType:      reposstore.ResourceTypeMemory,
				ResourceID:        "mem_1",
				RepoRole:          reposstore.RepoRolePrimary,
				Field:             repos.RepositoryNameFieldName,
				SuggestedRepoName: "runbooks-2",
				RepoName:          "runbooks.mem",
				RepoFullName:      "usr_1/runbooks.mem",
			},
		},
		{
			name:    "reserved suffix",
			err:     reservedSuffix,
			status:  http.StatusConflict,
			code:    repos.RepositoryReservedSuffixCode,
			message: "memory repository name override must not end with .mem",
			details: repos.RepositoryNameConflictDetails{
				Field:             repos.RepositoryNameFieldRepoNameOverride,
				SuggestedRepoName: "runbooks",
			},
		},
		{
			name:    "invalid override",
			err:     invalidOverride,
			status:  http.StatusBadRequest,
			code:    repos.RepositoryNameOverrideInvalidCode,
			message: "memory repository name override is invalid",
			details: repos.RepositoryNameConflictDetails{
				Field:             repos.RepositoryNameFieldRepoNameOverride,
				SuggestedRepoName: "runbooks",
			},
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			svc := &fakeMemoryService{createErr: test.err}
			mux := http.NewServeMux()
			RegisterRoutes(mux, NewMemoryHandler(svc), nil)
			req := httptest.NewRequest(http.MethodPost, "/api/v1/memory", bytes.NewBufferString(`{"name":"Runbooks"}`))
			req = req.WithContext(trusted.WithIdentity(req.Context(), trusted.Identity{Subject: "usr_1"}))
			req.Header.Set(meshxapi.HeaderWorkspaceID, "wsp_1")
			rec := httptest.NewRecorder()

			mux.ServeHTTP(rec, req)

			require.Equal(t, test.status, rec.Code, rec.Body.String())
			var body struct {
				Code    string                              `json:"error"`
				Message string                              `json:"message"`
				Details repos.RepositoryNameConflictDetails `json:"details"`
			}
			require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &body))
			require.Equal(t, test.code, body.Code)
			require.Equal(t, test.message, body.Message)
			require.Equal(t, test.details, body.Details)
		})
	}
}
