package app

import (
	"github.com/tidbcloud/AgentTeam/internal/store/app/registry"
	"net/http"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/api/testkit/httputil"
)

type fakeWorkspaceAppRealtime struct {
	workspaceAppsUpdated []string
	channelsUpdated      []string
}

func (realtime *fakeWorkspaceAppRealtime) EmitWorkspaceAppsUpdated(workspaceID string) {
	realtime.workspaceAppsUpdated = append(realtime.workspaceAppsUpdated, workspaceID)
}

func (realtime *fakeWorkspaceAppRealtime) EmitChannelUpdated(workspaceID string) {
	realtime.channelsUpdated = append(realtime.channelsUpdated, workspaceID)
}

func TestAppVisibilityUpdatePublishesAuthorizedCacheInvalidations(t *testing.T) {
	t.Parallel()

	fake := newFakeStore()
	fake.appVisibilityResult.RemovedChannelIDs = []string{"chn_1", "chn_2"}
	realtime := &fakeWorkspaceAppRealtime{}
	router := newAppRouter(Dependencies{AppStore: fake, Realtime: realtime})

	resp := httputil.DoJSON(
		t,
		router,
		http.MethodPatch,
		"/api/v1/workspaces/wsp_1/app-installations/ainst_1/catalog-visibility",
		map[string]any{"catalogVisibility": registry.CatalogVisibilityPrivate},
	)
	require.Equal(t, http.StatusOK, resp.Code)
	require.Equal(t, []string{"wsp_1"}, realtime.workspaceAppsUpdated)
	require.Equal(t, []string{"wsp_1"}, realtime.channelsUpdated)
}

func TestAppVisibilityUpdateWithoutRemovedChannelsPublishesOnlyAppRefresh(t *testing.T) {
	t.Parallel()

	fake := newFakeStore()
	realtime := &fakeWorkspaceAppRealtime{}
	router := newAppRouter(Dependencies{AppStore: fake, Realtime: realtime})

	resp := httputil.DoJSON(
		t,
		router,
		http.MethodPatch,
		"/api/v1/workspaces/wsp_1/app-installations/ainst_1/catalog-visibility",
		map[string]any{"catalogVisibility": registry.CatalogVisibilityPublic},
	)
	require.Equal(t, http.StatusOK, resp.Code)
	require.Equal(t, []string{"wsp_1"}, realtime.workspaceAppsUpdated)
	require.Empty(t, realtime.channelsUpdated)
}

func TestAppVisibilityPrivateRepairPublishesPayloadFreeChannelRefreshWithoutRemovedIDs(t *testing.T) {
	t.Parallel()

	fake := newFakeStore()
	realtime := &fakeWorkspaceAppRealtime{}
	router := newAppRouter(Dependencies{AppStore: fake, Realtime: realtime})

	resp := httputil.DoJSON(
		t,
		router,
		http.MethodPatch,
		"/api/v1/workspaces/wsp_1/app-installations/ainst_1/catalog-visibility",
		map[string]any{"catalogVisibility": registry.CatalogVisibilityPrivate},
	)
	require.Equal(t, http.StatusOK, resp.Code)
	require.Equal(t, []string{"wsp_1"}, realtime.workspaceAppsUpdated)
	require.Equal(t, []string{"wsp_1"}, realtime.channelsUpdated)
}

func TestAppVisibilityUpdateFailurePublishesNoRealtimeEvent(t *testing.T) {
	t.Parallel()

	fake := newFakeStore()
	fake.appVisibilityErr = errSentinel
	realtime := &fakeWorkspaceAppRealtime{}
	router := newAppRouter(Dependencies{AppStore: fake, Realtime: realtime})

	resp := httputil.DoJSON(
		t,
		router,
		http.MethodPatch,
		"/api/v1/workspaces/wsp_1/app-installations/ainst_1/catalog-visibility",
		map[string]any{"catalogVisibility": registry.CatalogVisibilityPrivate},
	)
	require.Equal(t, http.StatusInternalServerError, resp.Code)
	require.Empty(t, realtime.workspaceAppsUpdated)
	require.Empty(t, realtime.channelsUpdated)
}

func TestAppInstallationCreatePublishesWorkspaceAppRefresh(t *testing.T) {
	t.Parallel()

	fake := newFakeStore()
	realtime := &fakeWorkspaceAppRealtime{}
	router := newAppRouter(Dependencies{AppStore: fake, Realtime: realtime})

	resp := httputil.DoJSON(
		t,
		router,
		http.MethodPost,
		"/api/v1/workspaces/wsp_1/custom-apps",
		map[string]any{
			"slug":              "echo-app",
			"name":              "Echo App",
			"manifest":          map[string]any{},
			"catalogVisibility": registry.CatalogVisibilityPublic,
		},
	)
	require.Equal(t, http.StatusOK, resp.Code)
	require.Equal(t, []string{"wsp_1"}, realtime.workspaceAppsUpdated)
	require.Empty(t, realtime.channelsUpdated)
}

func TestAppInstallationCreateFailurePublishesNoRealtimeEvent(t *testing.T) {
	t.Parallel()

	fake := newFakeStore()
	fake.directAppErr = errSentinel
	realtime := &fakeWorkspaceAppRealtime{}
	router := newAppRouter(Dependencies{AppStore: fake, Realtime: realtime})

	resp := httputil.DoJSON(
		t,
		router,
		http.MethodPost,
		"/api/v1/workspaces/wsp_1/custom-apps",
		map[string]any{
			"slug":     "echo-app",
			"name":     "Echo App",
			"manifest": map[string]any{},
		},
	)
	require.Equal(t, http.StatusInternalServerError, resp.Code)
	require.Empty(t, realtime.workspaceAppsUpdated)
	require.Empty(t, realtime.channelsUpdated)
}
