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"
)

// dmMigrationLifecycleSmokeCase tests the complete lifecycle of a premium DM migration.
// It verifies the entire control path: Create → Running → Pause → Paused → Resume → Running → Delete.
type dmMigrationLifecycleSmokeCase struct {
	BaseCase
	dmValidator   *common.PremiumDMValidator
	cloudProvider CloudProviderType
}

// NewDMMigrationLifecycleSmokeCase creates a new migration lifecycle smoke test case.
func NewDMMigrationLifecycleSmokeCase(cloudProvider CloudProviderType) E2ECase {
	return &dmMigrationLifecycleSmokeCase{cloudProvider: cloudProvider}
}

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

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

func (m *dmMigrationLifecycleSmokeCase) 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 *dmMigrationLifecycleSmokeCase) 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.V1beta2PremiumDMTaskModeINCREMENTAL,
				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 INCREMENTAL-mode migration (stays running, ideal for lifecycle testing)
		Step("create premium DM migration", func() error {
			name := GenerateMigrationName("lifecycle")
			body := BuildCreateMigrationBody(
				name,
				dm_model.V1beta2PremiumDMTaskModeINCREMENTAL,
				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 for lifecycle test: %s", migrationID)
			return nil
		}).

		// Step 4: Verify migration can be listed
		Expect("premium DM migration appears in list", func() error {
			resp, err := m.dmValidator.Client().ListMigrations(tidbCluster, 100)
			if err != nil {
				return err
			}
			for _, migration := range resp.PremiumMigrations {
				if migration.MigrationID == migrationID {
					return nil
				}
			}
			return fmt.Errorf("migration %s not found in list", migrationID)
		}, 10, 30*time.Second).

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

		// Step 6: Verify migration details via GetMigration
		Step("verify migration details", func() error {
			migration, err := m.dmValidator.Client().GetMigration(tidbCluster, migrationID)
			if err != nil {
				return err
			}
			if migration.Mode == nil || *migration.Mode != dm_model.V1beta2PremiumDMTaskModeINCREMENTAL {
				return fmt.Errorf("migration mode is %v, expected %s", migration.Mode, dm_model.V1beta2PremiumDMTaskModeINCREMENTAL)
			}
			m.Logger().Info("migration details verified: mode=%s", *migration.Mode)
			return nil
		}).

		// Step 7: Pause the migration
		Step("pause premium DM migration", func() error {
			return m.dmValidator.Client().PauseMigration(tidbCluster, migrationID)
		}).

		// Step 8: Wait for migration to be paused
		Expect("premium DM migration is paused", func() error {
			return m.dmValidator.IsMigrationPaused(tidbCluster, migrationID)
		}, 20, DefaultExpectInterval).

		// Step 9: Resume the migration
		Step("resume premium DM migration", func() error {
			return m.dmValidator.Client().ResumeMigration(tidbCluster, migrationID)
		}).

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

		// Step 11: Delete the migration
		RetryDo("delete premium DM migration", func() error {
			return m.dmValidator.Client().DeleteMigration(tidbCluster, migrationID)
		}, DefaultRetryAttempts, DefaultRetryInterval).

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

	migrationID = ""
}
