package im

import (
	"net/http"
	"testing"

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

	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/store/message"
	unreadservice "github.com/tidbcloud/AgentTeam/internal/unread"
)

// TestNotificationSelfSetMuteEmitsZeroDeltaAndReactivationRefreshesRoster locks
// in the server-side mute → active/quiet unread recovery contract: only a
// normalized "mute" clears and suppresses with a zero unread delta, while
// active and quiet request a scope roster refresh and must not emit a
// fabricated zero delta.
func TestNotificationSelfSetMuteEmitsZeroDeltaAndReactivationRefreshesRoster(t *testing.T) {
	gin.SetMode(gin.TestMode)
	unread := &fakeUnreadRuntime{workspaceHasUnread: true}
	sink := &recordingUnreadSink{}
	panel := message.ScopeNotificationPanel{ScopeID: "chn_1", ScopeType: "channel"}
	handler := &ScopeExtrasHandler{
		streamWriter:         &recordingStreamWriter{},
		channelNotifications: fakeScopeNotificationStore{panel: panel},
		conversations: fakeConversationStore{item: message.ConversationItem{
			ScopeID: "chn_1",
			Kind:    message.ConversationKindChannel,
		}},
		unreadRuntime: unread,
		unreadSink:    sink,
	}

	// Mute clears + suppresses and emits exactly one zero delta.
	response, err := handler.NotificationsSelfSet(imWorkspaceJSON(dto.NotificationStateRequest{State: "mute"}, gin.Param{Key: "scopeId", Value: "chn_1"}))
	require.NoError(t, err)
	require.Equal(t, http.StatusOK, response.Status)
	require.Equal(t, []unreadservice.ScopeInvalidated{{
		WorkspaceID: "wsp_1",
		ScopeID:     "chn_1",
		MemberIDs:   []string{"mem_1"},
		Reason:      "channel_notification_self",
	}}, unread.invalidations)
	require.Len(t, sink.unreadUpdated, 1)
	require.Equal(t, int64(0), sink.unreadUpdated[0].Count)
	require.Equal(t, unreadservice.ServingStateStale, sink.unreadUpdated[0].ServingState)
	require.Len(t, unread.refreshes, 0)

	// Re-activation to active must not emit a fake zero delta; it refreshes the
	// scope roster instead.
	response, err = handler.NotificationsSelfSet(imWorkspaceJSON(dto.NotificationStateRequest{State: "active"}, gin.Param{Key: "scopeId", Value: "chn_1"}))
	require.NoError(t, err)
	require.Equal(t, http.StatusOK, response.Status)
	require.Len(t, sink.unreadUpdated, 1, "active re-activation must not emit another unread delta")
	require.Len(t, unread.invalidations, 1, "active re-activation must not re-suppress the scope")
	require.Len(t, unread.refreshes, 1)
	require.Equal(t, "chn_1", unread.refreshes[0].scopeID)
	require.Equal(t, unreadservice.ScopeTypeChannel, unread.refreshes[0].scopeType)
	require.Equal(t, []string{"mem_1"}, unread.refreshes[0].memberIDs)
}

func TestNotificationSelfSetQuietRefreshesRosterWithoutZeroDelta(t *testing.T) {
	gin.SetMode(gin.TestMode)
	unread := &fakeUnreadRuntime{}
	sink := &recordingUnreadSink{}
	panel := message.ScopeNotificationPanel{ScopeID: "thr_1", ScopeType: "thread"}
	handler := &ScopeExtrasHandler{
		streamWriter:        &recordingStreamWriter{},
		threadNotifications: fakeScopeNotificationStore{panel: panel},
		conversations: fakeConversationStore{item: message.ConversationItem{
			ScopeID: "thr_1",
			Kind:    message.ConversationKindThread,
		}},
		unreadRuntime: unread,
		unreadSink:    sink,
	}

	response, err := handler.NotificationsSelfSet(imWorkspaceJSON(dto.NotificationStateRequest{State: "quiet"}, gin.Param{Key: "scopeId", Value: "thr_1"}))
	require.NoError(t, err)
	require.Equal(t, http.StatusOK, response.Status)
	require.Len(t, sink.unreadUpdated, 0, "quiet must not emit an unread delta")
	require.Len(t, unread.invalidations, 0, "quiet must not suppress the scope")
	require.Len(t, unread.refreshes, 1)
	require.Equal(t, "thr_1", unread.refreshes[0].scopeID)
	require.Equal(t, unreadservice.ScopeTypeThread, unread.refreshes[0].scopeType)
	require.Equal(t, []string{"mem_1"}, unread.refreshes[0].memberIDs)
}
