package notification

import (
	"context"
	"strconv"
	"testing"

	"github.com/nlopes/slack"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"code.justin.tv/eventbus/controlplane/infrastructure/validation"
	itemMock "code.justin.tv/eventbus/controlplane/infrastructure/validation/mocks"
)

func newMockItem(id string) *itemMock.Item {
	i := &itemMock.Item{}
	i.On("ID").Return(id)
	i.On("Attributes").Return([]*validation.ItemAttribute{})
	i.On("Type").Return("CoolType")
	return i
}

type mockSlack struct {
	calls int
}

func (m *mockSlack) SendMessage(ctx context.Context, text string, attachments ...slack.Attachment) error {
	m.calls++
	return nil
}

func TestSlackAttachments(t *testing.T) {

	t.Run("attachments are batched to meet slack limits", func(t *testing.T) {
		ctx := context.Background()
		tts := []struct {
			numAttachments int
			expectedCalls  int
		}{
			{1, 1},
			{20, 1},
			{21, 2},
			{44, 3},
		}

		for _, tt := range tts {
			mockClient := &mockSlack{}
			actions := &slackActions{
				client: mockClient,
			}

			for i := 0; i < tt.numAttachments; i++ {
				item := newItem(strconv.Itoa(i))
				actions.attach(validation.Ok(item))
			}

			err := actions.sendAll(ctx)
			require.NoError(t, err)
			assert.Equal(t, tt.expectedCalls, mockClient.calls)
		}
	})

	t.Run("reset wipes internal attachments", func(t *testing.T) {
		actions := &slackActions{
			client: nil,
		}

		actions.attach(validation.Ok(newMockItem("foobar")))
		actions.attach(validation.Ok(newMockItem("garply")))
		actions.attach(validation.Ok(newMockItem("baz")))

		assert.Equal(t, 3, len(actions.okAttachments))

		actions.reset()
		assert.Equal(t, 0, len(actions.okAttachments))
	})
}
