package im

import (
	"context"
	"testing"

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

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

type reactionLifecycleGuardStub struct {
	active        bool
	calls         []reactionLifecycleGuardCall
	callbackCalls int
}

type reactionLifecycleGuardCall struct {
	workspaceID string
	scopeIDs    []string
}

func (guard *reactionLifecycleGuardStub) WithActiveTaskScopes(
	_ context.Context,
	workspaceID string,
	scopeIDs []string,
	publish func() error,
) (bool, error) {
	guard.calls = append(guard.calls, reactionLifecycleGuardCall{
		workspaceID: workspaceID,
		scopeIDs:    append([]string(nil), scopeIDs...),
	})
	if !guard.active {
		return false, nil
	}
	guard.callbackCalls++
	return true, publish()
}

func TestReactionsHandlerSuppressesDeletedTaskPublication(t *testing.T) {
	gin.SetMode(gin.TestMode)

	for _, mutation := range []struct {
		name string
		run  func(*ReactionsHandler) error
	}{
		{
			name: "add",
			run: func(handler *ReactionsHandler) error {
				_, err := handler.Add(imWorkspaceRequest(
					gin.Param{Key: "scopeId", Value: "tsk_stale_route"},
					gin.Param{Key: "messageId", Value: "msg_task_reaction"},
					gin.Param{Key: "emoji", Value: "👍"},
				))
				return err
			},
		},
		{
			name: "remove",
			run: func(handler *ReactionsHandler) error {
				_, err := handler.Remove(imWorkspaceRequest(
					gin.Param{Key: "scopeId", Value: "tsk_stale_route"},
					gin.Param{Key: "messageId", Value: "msg_task_reaction"},
					gin.Param{Key: "emoji", Value: "👍"},
				))
				return err
			},
		},
	} {
		t.Run(mutation.name, func(t *testing.T) {
			guard := &reactionLifecycleGuardStub{}
			streamWriter := &recordingStreamWriter{}
			handler := &ReactionsHandler{
				reactions: fakeReactionStore{
					changed:     true,
					channelID:   "tsk_task_reaction",
					channelType: message.ConversationKindTask,
				},
				streamWriter:       streamWriter,
				taskScopeLifecycle: guard,
			}

			require.NoError(t, mutation.run(handler))

			require.Equal(t, []reactionLifecycleGuardCall{{
				workspaceID: "wsp_1",
				scopeIDs:    []string{"tsk_task_reaction"},
			}}, guard.calls)
			require.Zero(t, guard.callbackCalls)
			require.Empty(t, streamWriter.scopeRequests)
		})
	}
}

func TestReactionsHandlerNonTaskPublicationBypassesTaskLifecycle(t *testing.T) {
	gin.SetMode(gin.TestMode)

	guard := &reactionLifecycleGuardStub{}
	streamWriter := &recordingStreamWriter{}
	handler := &ReactionsHandler{
		reactions: fakeReactionStore{
			changed:     true,
			channelID:   "chn_reaction",
			channelType: message.ConversationKindChannel,
		},
		streamWriter:       streamWriter,
		taskScopeLifecycle: guard,
	}

	_, err := handler.Add(imWorkspaceRequest(
		gin.Param{Key: "scopeId", Value: "tsk_stale_route"},
		gin.Param{Key: "messageId", Value: "msg_reaction"},
		gin.Param{Key: "emoji", Value: "👍"},
	))

	require.NoError(t, err)
	require.Empty(t, guard.calls)
	require.Zero(t, guard.callbackCalls)
	require.Len(t, streamWriter.scopeRequests, 1)
	require.Equal(t, "chn_reaction", streamWriter.scopeRequests[0].ScopeID)
}
