package server

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/module/modserver"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/module/modshared"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/module/notifications/rpc"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/matcher"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/mock_modserver"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/testlogger"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/pkg/event"
	"go.uber.org/mock/gomock"
	"google.golang.org/protobuf/proto"
)

var (
	_ modserver.Module        = &module{}
	_ modserver.Factory       = &Factory{}
	_ rpc.NotificationsServer = &server{}
)

func TestServer_GitPushEvent_SuccessfulPublish(t *testing.T) {
	// GIVEN
	// setup test fixtures
	ctrl := gomock.NewController(t)
	rpcAPI := mock_modserver.NewMockRPCAPI(ctrl)
	ctx := modshared.InjectRPCAPI(context.Background(), rpcAPI)

	var gotEvent proto.Message
	// setup server under test
	s := newServer(func(ctx context.Context, e proto.Message) error {
		gotEvent = e
		return nil
	})

	// WHEN
	gitPushEvent := &event.GitPushEvent{
		Project: &event.Project{Id: 42, FullPath: "foo/bar"},
	}
	_, err := s.GitPushEvent(ctx, &rpc.GitPushEventRequest{
		Event: gitPushEvent,
	})

	// THEN
	require.NoError(t, err)
	matcher.AssertProtoEqual(t, gotEvent, gitPushEvent)
}

func TestServer_GitPushEvent_FailedPublish(t *testing.T) {
	// GIVEN
	// setup test fixtures
	ctrl := gomock.NewController(t)
	rpcAPI := mock_modserver.NewMockRPCAPI(ctrl)
	ctx := modshared.InjectRPCAPI(context.Background(), rpcAPI)
	rpcAPI.EXPECT().Log().Return(testlogger.New(t))
	givenErr := errors.New("some error")
	rpcAPI.EXPECT().
		HandleProcessingError(gomock.Any(), gomock.Any(), givenErr)

	// setup server under test
	s := newServer(func(ctx context.Context, e proto.Message) error {
		return givenErr
	})

	// WHEN
	_, err := s.GitPushEvent(ctx, &rpc.GitPushEventRequest{
		Event: &event.GitPushEvent{
			Project: &event.Project{Id: 42, FullPath: "foo/bar"},
		},
	})

	// THEN
	assert.EqualError(t, err, "rpc error: code = Unavailable desc = failed to publish received git push event: some error")
}
