package dm

import (
	"fmt"
	"time"

	. "github.com/tidbcloud/dataflow-service-e2e/cases"
	"github.com/tidbcloud/dataflow-service-e2e/cases/premium/common"
	"github.com/tidbcloud/dataflow-service-e2e/internal/config"
	. "github.com/tidbcloud/dataflow-service-e2e/internal/model"
	dm_model "github.com/tidbcloud/dataflow-service-e2e/internal/tidbcloud/premium/consoleapi/dm/model"
)

// dmFullMigrationSmokeCase tests full migration (dump + load) for a premium DM migration.
// It covers:
// - Submit precheck and wait for completion
// - Create an ALL-mode migration
// - Wait for migration to start running
// - Wait for migration to finish (dump + load complete)
// - Delete the migration
type dmFullMigrationSmokeCase struct {
	BaseCase
	dmValidator   *common.PremiumDMValidator
	cloudProvider CloudProviderType
}

// NewDMFullMigrationSmokeCase creates a new full migration smoke test case.
func NewDMFullMigrationSmokeCase(cloudProvider CloudProviderType) E2ECase {
	return &dmFullMigrationSmokeCase{cloudProvider: cloudProvider}
}

func (m *dmFullMigrationSmokeCase) Name() string {
	return fmt.Sprintf("%sPremiumDMFullMigrationSmoke", m.cloudProvider)
}

func (m *dmFullMigrationSmokeCase) Tags() map[string]string {
	return map[string]string{TagKeyDomain: TagValueDomainDM}
}

func (m *dmFullMigrationSmokeCase) DeclareDependencyRequirements() map[string]DependencyRequirement {
	return map[string]DependencyRequirement{
		"premium": &TiDBPremiumRequirement{
			Dedicated: false,
			TiDBPremiumDimensions: TiDBPremiumDimensions{
				CloudProvider: m.cloudProvider,
				Region:        config.GlobalConfig.DefaultRegionOf(m.cloudProvider),
			},
		},
		"mysql": &MySQLRequirement{
			MySQLDimensions: MySQLDimensions{
				NetworkType: DataflowNetworkTypeNetworkTypePublic,
			},
		},
	}
}

func (m *dmFullMigrationSmokeCase) Run() {
	tidbCluster := m.TiDBPremium("premium")
	mysql := m.MySQL("mysql")
	m.dmValidator = common.NewPremiumDMValidator(m.Logger())

	var migrationID string
	var precheckID string

	// Cleanup: delete the created migration
	defer func() {
		if migrationID != "" {
			m.RetryDo(fmt.Sprintf("cleanup: delete premium migration %s", migrationID), func() error {
				return m.dmValidator.Client().DeleteMigration(tidbCluster, migrationID)
			}, DefaultRetryAttempts, DefaultRetryInterval)
		}
	}()

	m.
		// Step 1: Submit precheck
		Step("submit premium DM precheck", func() error {
			body := BuildPrecheckBody(
				GenerateMigrationName("pc"),
				dm_model.V1beta2PremiumDMTaskModeALL,
				dm_model.PremiumDMTaskImportModeENUMIMPORTMODELOGICAL,
				tidbCluster, mysql,
				DefaultDBForDMTest,
			)
			id, err := m.dmValidator.Client().CreatePrecheck(tidbCluster, body)
			if err != nil {
				return err
			}
			precheckID = id
			m.Logger().Info("precheck submitted: %s", precheckID)
			return nil
		}).

		// Step 2: Wait for precheck to complete
		Expect("precheck is done", func() error {
			return m.dmValidator.IsPrecheckDone(tidbCluster, precheckID)
		}, uint(PrecheckTimeout/(30*time.Second)), 30*time.Second).

		// Step 3: Create an ALL-mode migration
		Step("create ALL-mode premium DM migration", func() error {
			name := GenerateMigrationName("full")
			body := BuildCreateMigrationBody(
				name,
				dm_model.V1beta2PremiumDMTaskModeALL,
				dm_model.PremiumDMTaskImportModeENUMIMPORTMODELOGICAL,
				tidbCluster, mysql,
				DefaultDBForDMTest,
			)
			resp, err := m.dmValidator.Client().CreateMigration(tidbCluster, body)
			if err != nil {
				return err
			}
			migrationID = resp.Payload.MigrationID
			m.Logger().Info("created premium DM migration: %s", migrationID)
			return nil
		}).

		// Step 4: Wait for migration to start running
		Expect("premium DM migration is running", func() error {
			return m.dmValidator.IsMigrationRunning(tidbCluster, migrationID)
		}, DefaultExpectAttempts, DefaultExpectInterval).

		// Step 5: Wait for full data migration to complete (enters SYNC/incremental step)
		// ALL-mode migrations never reach FINISHED; they transition DUMP→LOAD→SYNC and stay RUNNING.
		Expect("premium DM migration full data complete (in SYNC step)", func() error {
			return m.dmValidator.IsMigrationInSyncStep(tidbCluster, migrationID)
		}, DefaultExpectAttempts, DefaultExpectInterval).

		// Step 6: Delete the migration (ALL-mode migrations must be explicitly deleted)
		RetryDo("delete premium DM migration", func() error {
			return m.dmValidator.Client().DeleteMigration(tidbCluster, migrationID)
		}, DefaultRetryAttempts, DefaultRetryInterval).

		// Step 7: Verify migration is deleted
		Expect("premium DM migration is deleted", func() error {
			return m.dmValidator.IsMigrationDeleted(tidbCluster, migrationID)
		}, 10, 30*time.Second)

	// Clear migrationID to skip cleanup since we already deleted it
	migrationID = ""
}
