package premium_dm

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/dataflow-service-ng/app/event_bus/publisher/center"
	"github.com/tidbcloud/dataflow-service-ng/app/repo/entity"
	"github.com/tidbcloud/eventbus-datastruct/event"
)

func TestConvertPremiumDMToDisplayEvent(t *testing.T) {
	task := &entity.PremiumDMTask{
		ID:         "tsk_abc",
		Name:       "migrate-1",
		Stage:      entity.PremiumDMTaskStageSourceCreating,
		Mode:       entity.PremiumDMTaskModeAll,
		ImportMode: entity.PremiumDMTaskImportModeLogical,
		TiDBID:     "12345",
		TenantID:   "67890",
		ProjectID:  "24680",
		CreatorID:  13579,
		Creator:    "user@example.com",
	}

	ev, err := convertPremiumDMToDisplayEvent(
		context.Background(), task, PremiumDMOperationCreate, event.EventStatusStarted,
	)
	require.NoError(t, err)
	require.Equal(t, string(entity.CreateDataMigration), ev.DisplayEventType)
	require.Equal(t, event.EventStatusStarted, ev.DisplayStatus)
	require.Equal(t, "tsk_abc", ev.ContextID)
	require.Equal(t, uint64(12345), ev.ClusterID)
	require.Equal(t, uint64(67890), ev.TenantID)
	require.Equal(t, uint64(24680), ev.ProjectID)
	require.Equal(t, uint64(13579), ev.AuthorID)
	require.Equal(t, "user@example.com", ev.Author)
	require.Equal(t,
		"The dm task creation started. Task ID: tsk_abc, Mode: all, Import Mode: logical.",
		ev.Summary,
	)

	detail, ok := ev.Detail.(*center.PremiumDMMsg)
	require.True(t, ok)
	require.Equal(t, "tsk_abc", detail.MigrationId)
	require.Equal(t, string(entity.PremiumDMTaskModeAll), detail.Mode)
}

func TestConvertPremiumDMOperationEvents(t *testing.T) {
	task := &entity.PremiumDMTask{
		ID:         "tsk_abc",
		Name:       "migrate-1",
		Stage:      entity.PremiumDMTaskStageStopped,
		Mode:       entity.PremiumDMTaskModeFull,
		ImportMode: entity.PremiumDMTaskImportModePhysical,
		TiDBID:     "1",
		TenantID:   "2",
		ProjectID:  "3",
	}

	tests := map[string]struct {
		operation PremiumDMOperation
		status    event.EventStatus
		eventType entity.DataflowEventType
	}{
		"delete started":   {operation: PremiumDMOperationDelete, status: event.EventStatusStarted, eventType: entity.DeleteDataMigration},
		"delete succeeded": {operation: PremiumDMOperationDelete, status: event.EventStatusSucceeded, eventType: entity.DeleteDataMigration},
		"create running":   {operation: PremiumDMOperationCreate, status: event.EventStatusRunning, eventType: entity.CreateDataMigration},
		"pause started":    {operation: PremiumDMOperationPause, status: event.EventStatusStarted, eventType: entity.PauseDataMigration},
		"pause succeeded":  {operation: PremiumDMOperationPause, status: event.EventStatusSucceeded, eventType: entity.PauseDataMigration},
		"pause canceled":   {operation: PremiumDMOperationPause, status: event.EventStatusCanceled, eventType: entity.PauseDataMigration},
		"pause failed":     {operation: PremiumDMOperationPause, status: event.EventStatusFailed, eventType: entity.PauseDataMigration},
		"resume started":   {operation: PremiumDMOperationResume, status: event.EventStatusStarted, eventType: entity.ResumeDataMigration},
		"resume succeeded": {operation: PremiumDMOperationResume, status: event.EventStatusSucceeded, eventType: entity.ResumeDataMigration},
		"resume canceled":  {operation: PremiumDMOperationResume, status: event.EventStatusCanceled, eventType: entity.ResumeDataMigration},
		"resume failed":    {operation: PremiumDMOperationResume, status: event.EventStatusFailed, eventType: entity.ResumeDataMigration},
		"create failed":    {operation: PremiumDMOperationCreate, status: event.EventStatusFailed, eventType: entity.CreateDataMigration},
	}
	for name, tc := range tests {
		t.Run(name, func(t *testing.T) {
			ev, err := convertPremiumDMToDisplayEvent(context.Background(), task, tc.operation, tc.status)
			require.NoError(t, err)
			require.Equal(t, tc.status, ev.DisplayStatus)
			require.Equal(t, string(tc.eventType), ev.DisplayEventType)
		})
	}
}

func TestConvertPremiumDMRejectsUnknownOperation(t *testing.T) {
	_, err := convertPremiumDMToDisplayEvent(context.Background(), &entity.PremiumDMTask{
		ID: "tsk_abc", TiDBID: "1", TenantID: "2", ProjectID: "3",
	}, PremiumDMOperation("unknown"), event.EventStatusStarted)
	require.EqualError(t, err, `unsupported premium dm operation "unknown"`)
}

func TestConvertPremiumDMDeletedIgnoresHistoricalTaskError(t *testing.T) {
	task := &entity.PremiumDMTask{
		ID:        "tsk_abc",
		Stage:     entity.PremiumDMTaskStageDeleted,
		TiDBID:    "1",
		TenantID:  "2",
		ProjectID: "3",
		ErrMsg:    "historical migration failure",
	}

	ev, err := convertPremiumDMToDisplayEvent(
		context.Background(), task, PremiumDMOperationDelete, event.EventStatusSucceeded,
	)
	require.NoError(t, err)
	require.Equal(t, event.EventStatusSucceeded, ev.DisplayStatus)

	detail, ok := ev.Detail.(*center.PremiumDMMsg)
	require.True(t, ok)
	require.Equal(t, "historical migration failure", detail.OriginalError)
}

func TestPublishPremiumDMEventNilPublisher(t *testing.T) {
	// Should not panic when publisher is unset.
	PublishPremiumDMEvent(context.Background(), nil, &entity.PremiumDMTask{
		ID: "tsk_x", TiDBID: "1", TenantID: "2",
		ProjectID: "3",
		Stage:     entity.PremiumDMTaskStageRunning,
	}, PremiumDMOperationCreate, event.EventStatusFailed)
}
