// +build integration

package storage_test

import (
	"testing"

	"code.justin.tv/live/autohost/internal/hosting/storage"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"

	"github.com/stretchr/testify/require"
)

func TestGetAndSetHost(t *testing.T) {
	testEnv := newTestEnv(t)
	storageClient := testEnv.storageClient

	sourceUserID := "1111111"
	targetUserID := "2222222"
	targetUserID2 := "3333333"

	t.Run("GetHost should return defaults when there is no item", func(t *testing.T) {
		testEnv.reset(t)

		// Verify that getting a host item that doesn't exist returns default values.
		ctx, cancel := getContextWithTimeout()
		defer cancel()
		dbHost, err := storageClient.GetHost(ctx, sourceUserID)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Empty(t, dbHost.HostingTargetID)
	})

	t.Run("SetHost create an item when none exists", func(t *testing.T) {
		testEnv.reset(t)

		// Create a host item.
		ctx, cancel := getContextWithTimeout()
		defer cancel()
		dbHost, err := storageClient.SetHost(ctx, sourceUserID, targetUserID)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Equal(t, targetUserID, dbHost.HostingTargetID)

		// Verify that we can fetch the item.
		ctx, cancel = getContextWithTimeout()
		defer cancel()
		dbHost, err = storageClient.GetHost(ctx, sourceUserID)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Equal(t, targetUserID, dbHost.HostingTargetID)
	})

	t.Run("SetHost should overwrite an existing item", func(t *testing.T) {
		testEnv.reset(t)

		// Set up: Create a host item.
		ctx, cancel := getContextWithTimeout()
		defer cancel()
		dbHost, err := storageClient.SetHost(ctx, sourceUserID, targetUserID)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Equal(t, targetUserID, dbHost.HostingTargetID)

		// Overwrite the item.
		ctx, cancel = getContextWithTimeout()
		defer cancel()
		dbHost, err = storageClient.SetHost(ctx, sourceUserID, targetUserID2)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Equal(t, targetUserID2, dbHost.HostingTargetID)

		// Verify that fetching the item gives the new values.
		ctx, cancel = getContextWithTimeout()
		defer cancel()
		dbHost, err = storageClient.GetHost(ctx, sourceUserID)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Equal(t, targetUserID2, dbHost.HostingTargetID)
	})
}

func TestDeleteHost(t *testing.T) {
	testEnv := newTestEnv(t)
	storageClient := testEnv.storageClient

	sourceUserID := "1111111"
	targetUserID := "2222222"

	t.Run("DeleteHost should work when there is no item", func(t *testing.T) {
		testEnv.reset(t)

		// Delete an item that doesn't exist.
		ctx, cancel := getContextWithTimeout()
		defer cancel()
		err := storageClient.DeleteHost(ctx, sourceUserID)
		require.NoError(t, err)

		// Getting the host item should return default values.
		ctx, cancel = getContextWithTimeout()
		defer cancel()
		dbHost, err := storageClient.GetHost(ctx, sourceUserID)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Empty(t, dbHost.HostingTargetID)
	})

	t.Run("DeleteHost should remove an existing item", func(t *testing.T) {
		testEnv.reset(t)

		// Add a host item.
		ctx, cancel := getContextWithTimeout()
		defer cancel()
		dbHost, err := storageClient.SetHost(ctx, sourceUserID, targetUserID)
		require.NoError(t, err)
		require.NotNil(t, dbHost)
		require.Equal(t, sourceUserID, dbHost.ChannelID)
		require.Equal(t, targetUserID, dbHost.HostingTargetID)

		// Delete the item
		ctx, cancel = getContextWithTimeout()
		defer cancel()
		err = storageClient.DeleteHost(ctx, sourceUserID)
		require.NoError(t, err)

		// Verify that the item has really been removed from the DynamoDB table.
		dynamoClient := testEnv.dynamoDBClient
		output, err := dynamoClient.GetItemWithContext(ctx, &dynamodb.GetItemInput{
			Key:       storage.HostTableKey(sourceUserID),
			TableName: aws.String(testEnv.hostTableName),
		})
		require.NoError(t, err)
		require.NotNil(t, output)
		require.Nil(t, output.Item)
	})
}
