// +build integration

package logic

import (
	"context"
	"testing"

	"code.justin.tv/live/autohost/internal/hosting/auth"
	"code.justin.tv/live/autohost/internal/hosting/pdms"
	"code.justin.tv/live/autohost/lib"
	"github.com/stretchr/testify/require"
)

func TestOnUserDestroy(t *testing.T) {
	t.Run("Confirms settings are removed when a UserDestroy event is received", func(t *testing.T) {
		mockPDMS := &pdms.MockClient{}

		testEnv := newTestEnv(t, &Params{
			Auth:       auth.NewAllowAllStub(),
			PDMSClient: mockPDMS,
		})

		logic := testEnv.logic
		userID := NewRandomUserID()
		otherUser := NewRandomUserID()
		otherUser2 := NewRandomUserID()

		strategy := lib.AutohostStrategyOrdered

		mockPDMS.On("PromiseDeletion", context.Background(), userID).Return(nil)

		// Update settings
		settings, err := logic.UpdateSettings(context.Background(), userID, userID, &lib.UpdateSettingsInput{
			Enabled:             boolPtr(true),
			TeamHost:            boolPtr(true),
			Strategy:            &strategy,
			DeprioritizeVodcast: boolPtr(true),
		})

		require.NoError(t, err)
		require.NotNil(t, settings)

		// Add items to the autohost list
		_, err = logic.SetList(context.Background(), userID, userID, []string{otherUser})
		require.NoError(t, err)

		// Add items to the added list by setting the list for a different user container the target user
		_, err = logic.SetList(context.Background(), otherUser, otherUser, []string{userID, otherUser2})
		require.NoError(t, err)

		// Send user destroy callback
		err = logic.OnUserDestroyEventReceived(context.Background(), userID)
		require.NoError(t, err)

		// Ensure pdms was called
		mockPDMS.AssertCalled(t, "PromiseDeletion", context.Background(), userID)

		// Get settings. Since the GetSettings call always returns an object, we need to confirm
		// default values are set.
		fetchedSettings, err := logic.GetSettings(context.Background(), userID, userID)
		require.NoError(t, err)
		require.NotNil(t, fetchedSettings)
		require.Equal(t, fetchedSettings.Enabled, false)
		require.Equal(t, fetchedSettings.TeamHost, false)
		require.Equal(t, fetchedSettings.DeprioritizeVodcast, false)
		require.Equal(t, fetchedSettings.Strategy, lib.AutohostStrategyRandom)
		require.Equal(t, fetchedSettings.CanBeRaidedBy, lib.CanBeRaidedByAll)

		// Get AddedList and confirm null
		fetchedList, err := logic.GetList(context.Background(), userID)
		require.NoError(t, err)
		require.Empty(t, fetchedList)

		// Get AddedList and confirm null
		fetchedAddedList, err := testEnv.storageClient.GetAddedList(context.Background(), userID)
		require.NoError(t, err)
		require.Empty(t, fetchedAddedList)

		// Verify that the deleted user is removed from other channel's autohost lists.
		otherUserList, err := logic.GetList(context.Background(), otherUser)
		require.NoError(t, err)
		require.Equal(t, []string{otherUser2}, otherUserList)
	})

	t.Run("Confirms no error if dynamodb row doesn't exist", func(t *testing.T) {
		testEnv := newTestEnv(t, &Params{
			Auth: auth.NewAllowAllStub(),
		})

		logic := testEnv.logic
		userID := NewRandomUserID()

		// Send user destroy callback
		err := logic.OnUserDestroyEventReceived(context.Background(), userID)
		require.NoError(t, err)

		// Get settings. Since the GetSettings call always returns an object, we need to confirm
		// default values are set.
		fetchedSettings, err := logic.GetSettings(context.Background(), userID, userID)
		require.NoError(t, err)
		require.NotNil(t, fetchedSettings)
		require.Equal(t, fetchedSettings.Enabled, false)
		require.Equal(t, fetchedSettings.TeamHost, false)
		require.Equal(t, fetchedSettings.DeprioritizeVodcast, false)
		require.Equal(t, fetchedSettings.Strategy, lib.AutohostStrategyRandom)
		require.Equal(t, fetchedSettings.CanBeRaidedBy, lib.CanBeRaidedByAll)

		// Get hosting List and confirm null
		fetchedList, err := logic.GetList(context.Background(), userID)
		require.NoError(t, err)
		require.Len(t, fetchedList, 0)
	})

	t.Run("Confirms OnUserDestroyEventReceived deletes hosting state", func(t *testing.T) {
		testEnv := newTestEnv(t, &Params{
			Auth: auth.NewAllowAllStub(),
		})

		logic := testEnv.logic
		sourceUserID := NewRandomUserID()
		targetUserID := NewRandomUserID()

		// Set up: Have a channel host another.
		ctx, cancel := getContextWithTimeout()
		defer cancel()
		// TODO: Replace with logic.HostTarget() when Autohost implements hosting (instead of proxying to Clue.)
		_, err := testEnv.storageClient.SetHost(ctx, sourceUserID, targetUserID)
		require.NoError(t, err)

		// Send user destroy callback
		ctx, cancel = getContextWithTimeout()
		defer cancel()
		err = logic.OnUserDestroyEventReceived(ctx, sourceUserID)
		require.NoError(t, err)

		// Verify that fetching hosting info returns default values.
		ctx, cancel = getContextWithTimeout()
		defer cancel()
		// TODO: Replace with logic.GetHost() when Autohost implements hosting (instead of proxying to Clue.)
		dbHost, err := testEnv.storageClient.GetHost(ctx, sourceUserID)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Empty(t, dbHost.HostingTargetID)
	})
}
