package consumer

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/pkgv2/bizerr"
	clusterevent "github.com/tidbcloud/tidb-management-service/utilities/clusterevent"

	mgmt "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
)

type testCMEventHandler struct {
	name     string
	match    bool
	executed bool
}

func (h *testCMEventHandler) Name() string {
	return h.name
}

func (h *testCMEventHandler) Match(event *clusterevent.ClusterEvent) bool {
	return h.match
}

func (h *testCMEventHandler) Execute(ctx context.Context, event *clusterevent.ClusterEvent, cluster *mgmt.Cluster) error {
	h.executed = true
	return nil
}

func TestCMEventHandlerSerialDispatcherExecuteSkipsClusterLookupWhenNoHandlerMatched(t *testing.T) {
	originalGetClusterByID := getClusterByID
	t.Cleanup(func() {
		getClusterByID = originalGetClusterByID
	})

	getClusterByIDCalled := false
	getClusterByID = func(ctx context.Context, clusterID uint64) (*mgmt.Cluster, bizerr.BizError) {
		getClusterByIDCalled = true
		return &mgmt.Cluster{ClusterId: clusterID}, nil
	}

	dispatcher := &CMEventHandlerSerialDispatcher{}
	handler := &testCMEventHandler{name: "test-handler", match: false}
	dispatcher.Register(handler)

	err := dispatcher.Execute(&clusterevent.ClusterEvent{
		ClusterID: 1,
		EventType: clusterevent.EventTypePaused,
	})

	require.NoError(t, err)
	require.False(t, getClusterByIDCalled)
	require.False(t, handler.executed)
}

func TestCMEventHandlerSerialDispatcherExecuteLooksUpClusterForMatchedHandler(t *testing.T) {
	originalGetClusterByID := getClusterByID
	t.Cleanup(func() {
		getClusterByID = originalGetClusterByID
	})

	getClusterByIDCalled := false
	getClusterByID = func(ctx context.Context, clusterID uint64) (*mgmt.Cluster, bizerr.BizError) {
		getClusterByIDCalled = true
		return &mgmt.Cluster{ClusterId: clusterID}, nil
	}

	dispatcher := &CMEventHandlerSerialDispatcher{}
	handler := &testCMEventHandler{name: "test-handler", match: true}
	dispatcher.Register(handler)

	err := dispatcher.Execute(&clusterevent.ClusterEvent{
		ClusterID: 1,
		EventType: clusterevent.EventTypeResumed,
	})

	require.NoError(t, err)
	require.True(t, getClusterByIDCalled)
	require.True(t, handler.executed)
}
