package errs

import (
	"errors"
	"net/http"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestNew_BasicShape(t *testing.T) {
	e := New(CodeInvalidInput, "字段缺失")
	require.Equal(t, CodeInvalidInput, e.Code)
	require.Equal(t, "字段缺失", e.Message)
	require.Nil(t, e.Cause)
}

func TestWithFields(t *testing.T) {
	e := New(CodeInvalidInput, "x").WithFields(map[string]any{"name": "required"})
	require.Equal(t, "required", e.Fields["name"])
}

func TestWrap_PreservesCause(t *testing.T) {
	cause := errors.New("boom")
	e := Wrap(cause, CodeInternal, "wrapped")
	require.ErrorIs(t, e, cause)
	require.Equal(t, "wrapped: boom", e.Error())
}

func TestHTTPStatus(t *testing.T) {
	cases := map[Code]int{
		CodeInvalidInput:            http.StatusBadRequest,
		CodeUnauthorized:            http.StatusUnauthorized,
		CodeForbidden:               http.StatusForbidden,
		CodeNotFound:                http.StatusNotFound,
		CodeConflict:                http.StatusConflict,
		CodeProjectSlugTaken:        http.StatusConflict,
		CodeProjectArchived:         http.StatusConflict,
		CodeRequirementClosed:       http.StatusConflict,
		CodePhaseGateFailed:         http.StatusConflict,
		CodeRateLimited:             http.StatusTooManyRequests,
		CodeUpstream:                http.StatusBadGateway,
		CodeUnavailable:             http.StatusServiceUnavailable,
		CodeInternal:                http.StatusInternalServerError,
		CodeWorkspaceSlugTaken:      http.StatusConflict,
		CodeWorkspaceSyncInProgress: http.StatusConflict,
		CodeWorktreeBranchConflict:  http.StatusConflict,
		CodeWorktreeAlreadyActive:   http.StatusConflict,
		CodeWorkspaceCloneFailed:    http.StatusBadGateway,
		CodeGitCmdFailed:            http.StatusBadGateway,
		CodeWorkspaceRemoteInvalid:  http.StatusBadRequest,
		CodeWorktreePathInvalid:     http.StatusBadRequest,
		CodeGitCredentialInvalid:    http.StatusBadRequest,
		CodeWorktreeNotHeldByCaller: http.StatusForbidden,
		// Chat codes
		CodeChatConversationNotFound:      http.StatusNotFound,
		CodeChatMessageNotFound:           http.StatusNotFound,
		CodeChatMessageNotPending:         http.StatusConflict,
		CodeChatConcurrentMessage:         http.StatusConflict,
		CodeChatAttachmentTooLarge:        http.StatusRequestEntityTooLarge,
		CodeChatAttachmentUnsupportedMime: http.StatusUnsupportedMediaType,
		CodeChatModelCapabilityMismatch:   http.StatusConflict,
		CodeChatTemplateNotFound:          http.StatusNotFound,
		CodeChatEndpointNotFound:          http.StatusNotFound,
		CodeChatModelNotFound:             http.StatusNotFound,
		// LLM codes
		CodeLLMUpstream:       http.StatusBadGateway,
		CodeLLMTimeout:        http.StatusGatewayTimeout,
		CodeLLMRateLimited:    http.StatusTooManyRequests,
		CodeLLMContextTooLong: http.StatusBadRequest,
		// Storage codes
		CodeStoragePutFailed: http.StatusBadGateway,
		CodeStorageGetFailed: http.StatusBadGateway,
		// Jobs codes
		CodeJobNotFound:          http.StatusNotFound,
		CodeJobInvalidType:       http.StatusBadRequest,
		CodeJobPayloadInvalid:    http.StatusBadRequest,
		CodeJobPayloadTooLarge:   http.StatusBadRequest,
		CodeWebhookNotConfigured: http.StatusServiceUnavailable,
	}
	for code, want := range cases {
		require.Equal(t, want, HTTPStatus(code), "code=%s", code)
	}
}
