package main

import (
	"context"
	"testing"

	"code.justin.tv/beefcake/server/internal/config"
	"code.justin.tv/beefcake/server/internal/legacyperm/legacypermmocks"
	"code.justin.tv/beefcake/server/internal/role"
	"code.justin.tv/beefcake/server/internal/testconfig"
	"github.com/aws/aws-lambda-go/events"
	"github.com/stretchr/testify/mock"
)

type handlerTest struct {
	Handler           *handler
	Config            *config.Config
	LegacyPermissions *legacypermmocks.LegacyPermissionsAPI
}

func newHandlerTest(t *testing.T) *handlerTest {
	config := testconfig.New(t)
	legacyPermissions := new(legacypermmocks.LegacyPermissionsAPI)
	return &handlerTest{
		Handler: &handler{
			Config:            config,
			LegacyPermissions: legacyPermissions,
		},
		Config:            config,
		LegacyPermissions: legacyPermissions,
	}
}

func (ht *handlerTest) Teardown(t *testing.T) {
	ht.LegacyPermissions.AssertExpectations(t)
}

func TestHandler(t *testing.T) {
	const testRoleID = "testRoleID"
	const testRoleName = "testRoleName"

	testCases := []struct {
		CaseName string

		OldRoleID      string
		OldPermissions []string
		NewRoleID      string
		NewPermissions []string

		AddedPermissions   []string
		RemovedPermissions []string
	}{
		{
			CaseName:           "role created",
			OldRoleID:          "",
			OldPermissions:     []string{},
			NewRoleID:          testRoleID,
			NewPermissions:     []string{},
			AddedPermissions:   []string{},
			RemovedPermissions: []string{},
		},
		{
			CaseName:       "first permission added",
			OldRoleID:      testRoleID,
			OldPermissions: []string{},
			NewRoleID:      testRoleID,
			NewPermissions: []string{
				"perm1",
			},
			AddedPermissions: []string{
				"perm1",
			},
			RemovedPermissions: []string{},
		},
		{
			CaseName:  "first permission removed",
			OldRoleID: testRoleID,
			OldPermissions: []string{
				"perm1",
			},
			NewRoleID:        testRoleID,
			NewPermissions:   []string{},
			AddedPermissions: []string{},
			RemovedPermissions: []string{
				"perm1",
			},
		},
		{
			CaseName:  "permission added",
			OldRoleID: testRoleID,
			OldPermissions: []string{
				"perm1",
			},
			NewRoleID: testRoleID,
			NewPermissions: []string{
				"perm1",
				"perm2",
			},
			AddedPermissions: []string{
				"perm1",
				"perm2",
			},
			RemovedPermissions: []string{},
		},
		{
			CaseName:  "permission removed",
			OldRoleID: testRoleID,
			OldPermissions: []string{
				"perm1",
				"perm2",
			},
			NewRoleID: testRoleID,
			NewPermissions: []string{
				"perm1",
			},
			AddedPermissions: []string{
				"perm1",
			},
			RemovedPermissions: []string{
				"perm2",
			},
		},
		{
			CaseName:  "role deleted with permissions",
			OldRoleID: testRoleID,
			OldPermissions: []string{
				"perm1",
			},
			NewRoleID:        "",
			NewPermissions:   []string{},
			AddedPermissions: []string{},
			RemovedPermissions: []string{
				"perm1",
			},
		},
		{
			CaseName:           "role deleted",
			OldRoleID:          testRoleID,
			OldPermissions:     []string{},
			NewRoleID:          "",
			NewPermissions:     []string{},
			AddedPermissions:   []string{},
			RemovedPermissions: []string{},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.CaseName, func(t *testing.T) {
			ht := newHandlerTest(t)
			defer ht.Teardown(t)

			for _, m := range tc.AddedPermissions {
				ht.LegacyPermissions.
					On("AddRole", mock.Anything, m, testRoleID, testRoleName).
					Return(nil).
					Once()
			}

			for _, m := range tc.RemovedPermissions {
				ht.LegacyPermissions.
					On("RemoveRole", mock.Anything, m, testRoleID).
					Return(nil).
					Once()
			}

			ht.Handler.Handle(context.Background(), events.DynamoDBEvent{
				Records: []events.DynamoDBEventRecord{
					{
						Change: events.DynamoDBStreamRecord{
							OldImage: map[string]events.DynamoDBAttributeValue{
								ht.Config.RolesHashKey.Get():    events.NewStringAttribute(tc.OldRoleID),
								role.NameAttribute:              events.NewStringAttribute(testRoleName),
								role.LegacyPermissionsAttribute: events.NewStringSetAttribute(tc.OldPermissions),
							},
							NewImage: map[string]events.DynamoDBAttributeValue{
								ht.Config.RolesHashKey.Get():    events.NewStringAttribute(tc.NewRoleID),
								role.NameAttribute:              events.NewStringAttribute(testRoleName),
								role.LegacyPermissionsAttribute: events.NewStringSetAttribute(tc.NewPermissions),
							},
						},
					},
				},
			})
		})
	}
}
