package backup

import (
	"fmt"
	"time"

	. "github.com/tidbcloud/dataflow-service-e2e/cases"
	"github.com/tidbcloud/dataflow-service-e2e/cases/dedicated/common"
	"github.com/tidbcloud/dataflow-service-e2e/internal/config"
	. "github.com/tidbcloud/dataflow-service-e2e/internal/model"
	"github.com/tidbcloud/dataflow-service-e2e/internal/tidbcloud/dedicated/consoleapi"
	br_model "github.com/tidbcloud/dataflow-service-e2e/internal/tidbcloud/dedicated/consoleapi/br/model"
)

// snapshotBackupSmokeCase tests snapshot backup functionality for a TiDB Dedicated cluster.
// It covers:
// - Create a manual snapshot backup
// - Wait for backup to complete
// - Verify backup appears in list
// - Delete backup
type snapshotBackupSmokeCase struct {
	BaseCase
	backupValidator *common.BackupValidator
	cloudProvider   CloudProviderType
}

// NewSnapshotBackupSmokeCase creates a new snapshot backup smoke test case.
func NewSnapshotBackupSmokeCase(cloudProvider CloudProviderType) E2ECase {
	return &snapshotBackupSmokeCase{cloudProvider: cloudProvider}
}

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

func (m *snapshotBackupSmokeCase) Tags() map[string]string {
	return map[string]string{TagKeyDomain: TagValueDomainBR}
}

func (m *snapshotBackupSmokeCase) DeclareDependencyRequirements() map[string]DependencyRequirement {
	return map[string]DependencyRequirement{
		"tidb": &TiDBDedicatedRequirement{
			Dedicated: true,
			TiDBDedicatedDimensions: TiDBDedicatedDimensions{
				CloudProvider: m.cloudProvider,
				Region:        config.GlobalConfig.DefaultRegionOf(m.cloudProvider),
			},
		},
	}
}

func (m *snapshotBackupSmokeCase) Run() {
	const (
		backupTimeout = 30 * time.Minute
		retentionDays = 1
	)

	tidbCluster := m.TiDBDedicated("tidb")
	backupName := GenerateBackupName("e2e-snapshot")

	// Initialize validator
	m.backupValidator = common.NewBackupValidator(m.Logger())

	var backupID uint64

	// Cleanup: delete the created backup
	defer func() {
		if backupID > 0 {
			m.RetryDo(fmt.Sprintf("cleanup: delete test backup %d(%s)", backupID, backupName), func() error {
				return m.backupValidator.Client().DeleteBackup(tidbCluster, backupID)
			}, 3, time.Minute).
				Expect("backup is deleted", func() error {
					return m.backupValidator.IsBackupNotInList(tidbCluster, backupID)
				}, 5, time.Minute)
		}
	}()

	m.
		// Step 1: List existing backups
		Step("list existing backups", func() error {
			resp, err := m.backupValidator.Client().ListBackups(tidbCluster, 1, 10)
			if err != nil {
				return err
			}
			m.Logger().Info("existing backups count: %d", resp.Total)
			return nil
		}).

		// Step 2: Create a manual snapshot backup
		RetryDo("create manual snapshot backup", func() error {
			req := &consoleapi.CreateBackupScheduleRequest{
				Name:            backupName,
				Description:     "E2E test snapshot backup",
				BackupType:      "MANUAL",
				BackupTime:      time.Now().Format(time.RFC3339),
				BackupMode:      "SNAPSHOT",
				RetentionPeriod: retentionDays,
			}
			resp, err := m.backupValidator.Client().CreateBackupSchedule(tidbCluster, req)
			if err != nil {
				return err
			}
			backupID = resp.Id
			m.Logger().Info("created backup with ID: %d, name: %s", backupID, backupName)
			return nil
		}, 3, time.Minute).

		// Step 3: Verify backup appears in list
		Expect("backup is in list", func() error {
			return m.backupValidator.IsBackupInList(tidbCluster, backupID)
		}, 5, time.Second*30).

		// Step 4: Wait for backup to complete
		Step("wait for backup to complete", func() error {
			return m.backupValidator.WaitForBackupComplete(tidbCluster, backupID, backupTimeout)
		}).

		// Step 5: Verify backup status is SUCCESS
		Expect("backup status is SUCCESS", func() error {
			return m.backupValidator.IsBackupInStatus(tidbCluster, backupID, string(br_model.DataflowBackupExportStatusSUCCESS))
		}, 3, time.Second*10).

		// Step 6: Delete the backup
		RetryDo("delete backup", func() error {
			return m.backupValidator.Client().DeleteBackup(tidbCluster, backupID)
		}, 3, time.Minute).

		// Step 7: Verify backup is deleted
		Expect("backup is not in list", func() error {
			return m.backupValidator.IsBackupNotInList(tidbCluster, backupID)
		}, 5, time.Minute)

	// Clear backupID to skip cleanup since we already deleted it
	backupID = 0
}
