package teamworkflow

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

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/store/identity"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
	"github.com/tidbcloud/AgentTeam/internal/store/workspace"
)

// TestTeamWorkflowProtectedSelectorHTTPMatrix proves the real Team Workflow HTTP
// handler projects one byte-identical 404 team_workflow_not_found contract for a
// missing selector and a cross-tenant/forbidden one, across raw store and wrapped
// canonical failures, with no verbatim store text leaked.
func TestTeamWorkflowProtectedSelectorHTTPMatrix(t *testing.T) {
	gin.SetMode(gin.TestMode)

	rawMissing := teamWorkflowSelectorHTTPResponse(t, storeerr.NotFound("Team Workflow twf_secret is missing"))
	rawForbidden := teamWorkflowSelectorHTTPResponse(t, storeerr.Forbidden("Team Workflow twf_secret is forbidden"))
	wrappedMissing := teamWorkflowSelectorHTTPResponse(t, &codedStoreError{kind: storeerr.ErrNotFound, message: "Team Workflow twf_secret is missing"})
	wrappedForbidden := teamWorkflowSelectorHTTPResponse(t, &codedStoreError{kind: storeerr.ErrForbidden, message: "Team Workflow twf_secret is forbidden"})

	responses := []*httptest.ResponseRecorder{rawMissing, rawForbidden, wrappedMissing, wrappedForbidden}
	for _, response := range responses {
		require.Equal(t, http.StatusNotFound, response.Code)
		require.Contains(t, response.Body.String(), `"code":"team_workflow_not_found"`)
		require.Contains(t, response.Body.String(), `"stage":"team_workflow"`)
		require.NotContains(t, response.Body.String(), "twf_secret")
	}
	for _, response := range responses[1:] {
		require.JSONEq(t, responses[0].Body.String(), response.Body.String())
	}
}

// codedStoreError is a wrapped store error carrying a stable Team Workflow code
// so the wrapped path is exercised through the real classifier.
type codedStoreError struct {
	kind    error
	message string
}

func (err *codedStoreError) Error() string { return err.message }
func (err *codedStoreError) Unwrap() error { return err.kind }

func teamWorkflowSelectorHTTPResponse(t *testing.T, selectorErr error) *httptest.ResponseRecorder {
	t.Helper()
	handlers := newRouteHandlers(&fakeService{err: selectorErr})
	router := gin.New()
	router.GET("/teams/:teamId/workflows/:teamWorkflowId",
		func(ctx *gin.Context) {
			api.SetAuthenticatedUser(ctx, identity.AuthenticatedUser{User: identity.User{ID: "usr_1"}})
			api.SetCurrentWorkspace(ctx, workspace.Summary{WorkspaceID: "wsp_1", MemberID: "mem_1", MemberUserID: "usr_1", WorkspaceRole: "owner"})
		},
		api.HandleWorkspaceScoped(handlers.detail.Get, api.WithErrorClassifier(classifyError)),
	)

	request := httptest.NewRequest(http.MethodGet, "/teams/team_secret/workflows/twf_secret", http.NoBody)
	recorder := httptest.NewRecorder()
	router.ServeHTTP(recorder, request)

	var body map[string]any
	require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &body))
	require.Equal(t, "team_workflow_not_found", body["code"])
	return recorder
}

// TestTeamWorkflowUnknownFailureFailsClosedThroughRouter proves an unknown
// internal failure through the real handler fails closed to a generic 500 and
// never projects the raw error text.
func TestTeamWorkflowUnknownFailureFailsClosedThroughRouter(t *testing.T) {
	gin.SetMode(gin.TestMode)
	handlers := newRouteHandlers(&fakeService{err: &unknownCauseError{}})
	router := gin.New()
	router.GET("/teams/:teamId/workflows/:teamWorkflowId",
		func(ctx *gin.Context) {
			api.SetAuthenticatedUser(ctx, identity.AuthenticatedUser{User: identity.User{ID: "usr_1"}})
			api.SetCurrentWorkspace(ctx, workspace.Summary{WorkspaceID: "wsp_1", MemberID: "mem_1", MemberUserID: "usr_1", WorkspaceRole: "owner"})
		},
		api.HandleWorkspaceScoped(handlers.detail.Get, api.WithErrorClassifier(classifyError)),
	)
	request := httptest.NewRequest(http.MethodGet, "/teams/team_1/workflows/twf_1", http.NoBody)
	recorder := httptest.NewRecorder()
	router.ServeHTTP(recorder, request)
	require.Equal(t, http.StatusInternalServerError, recorder.Code)
	require.NotContains(t, recorder.Body.String(), "internal_sql")
	require.NotContains(t, recorder.Body.String(), "SELECT")
}

type unknownCauseError struct{}

func (err *unknownCauseError) Error() string {
	return "internal_sql: SELECT secret FROM team_workflows WHERE tenant_id='acme'"
}
