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

// dualRegionBackupSmokeCase tests dual-region backup functionality.
// It covers:
// - Query backup settings to check current region configuration
// - Verify dual-region is supported (whitelisted)
// - Configure dual-region backup if enabled
// - Verify backup settings reflect dual-region configuration
type dualRegionBackupSmokeCase struct {
	BaseCase
	backupValidator *common.BackupValidator
	cloudProvider   CloudProviderType
}

// NewDualRegionBackupSmokeCase creates a new dual-region backup smoke test case.
func NewDualRegionBackupSmokeCase(cloudProvider CloudProviderType) E2ECase {
	return &dualRegionBackupSmokeCase{cloudProvider: cloudProvider}
}

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

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

func (m *dualRegionBackupSmokeCase) 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 *dualRegionBackupSmokeCase) Run() {
	tidbCluster := m.TiDBDedicated("tidb")

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

	m.
		// Step 1: Query current backup settings including region configuration
		Step("query backup settings with region info", func() error {
			resp, err := m.backupValidator.Client().QueryBackupSetting(tidbCluster)
			if err != nil {
				return err
			}
			m.Logger().Info("backup status: %s", resp.Status)
			m.Logger().Info("available actions: %v", resp.Actions)
			m.Logger().Info("configured regions: %d", len(resp.Regions))
			for _, r := range resp.Regions {
				m.Logger().Info("  region: name=%s, displayName=%s", r.Name, r.DisplayName)
			}
			return nil
		}).

		// Step 2: Check if dual-region is supported (Edit_Region action available)
		Step("check dual-region support", func() error {
			resp, err := m.backupValidator.Client().QueryBackupSetting(tidbCluster)
			if err != nil {
				return err
			}
			// Check if Edit_Region action is available
			for _, action := range resp.Actions {
				if action == string(br_model.DataflowBackupSettingActionTypeEditRegion) {
					m.Logger().Info("dual-region configuration is supported (Edit_Region action available)")
					return nil
				}
			}
			m.Logger().Info("dual-region may not be whitelisted for this cluster (Edit_Region action not found)")
			// Don't fail the test, just log the finding
			return nil
		}).

		// Step 3: If dual-region is supported, configure it
		Step("configure dual-region (if supported)", func() error {
			resp, err := m.backupValidator.Client().QueryBackupSetting(tidbCluster)
			if err != nil {
				return err
			}

			// Check if dual-region editing is allowed
			canEditRegion := false
			for _, action := range resp.Actions {
				if action == string(br_model.DataflowBackupSettingActionTypeEditRegion) {
					canEditRegion = true
					break
				}
			}

			if !canEditRegion {
				m.Logger().Info("skipping dual-region configuration - not supported for this cluster")
				return nil
			}

			// Get secondary region based on cloud provider
			secondaryRegion := m.getSecondaryRegion(tidbCluster.Region)
			if secondaryRegion == "" {
				m.Logger().Info("no secondary region configured for %s, skipping", tidbCluster.Region)
				return nil
			}

			// Configure dual-region
			req := &consoleapi.ModifyBackupSettingRequest{
				Regions: []*consoleapi.RegionInfoRequest{
					{Name: tidbCluster.Region},
					{Name: secondaryRegion},
				},
			}
			err = m.backupValidator.Client().ModifyBackupSetting(tidbCluster, req)
			if err != nil {
				m.Logger().Warn("failed to configure dual-region: %s", err.Error())
				// Don't fail - cluster may not be whitelisted
				return nil
			}
			m.Logger().Info("configured dual-region: primary=%s, secondary=%s",
				tidbCluster.Region, secondaryRegion)
			return nil
		}).

		// Step 4: Verify dual-region configuration
		Expect("dual-region is configured", func() error {
			resp, err := m.backupValidator.Client().QueryBackupSetting(tidbCluster)
			if err != nil {
				return err
			}

			if len(resp.Regions) >= 2 {
				m.Logger().Info("dual-region verified: %d regions configured", len(resp.Regions))
				return nil
			}

			m.Logger().Info("single region configured (dual-region may not be enabled)")
			// Don't fail - this is informational
			return nil
		}, 3, time.Second*10)
}

// getSecondaryRegion returns a suitable secondary region for dual-region backup
func (m *dualRegionBackupSmokeCase) getSecondaryRegion(primaryRegion string) string {
	// Region mappings for dual-region backup
	regionPairs := map[string]string{
		// AWS regions
		"us-west-2":      "us-west-1",
		"us-west-1":      "us-west-2",
		"us-east-1":      "us-east-2",
		"us-east-2":      "us-east-1",
		"eu-west-1":      "eu-west-2",
		"ap-southeast-1": "ap-southeast-2",
		// GCP regions
		"us-west1":        "us-central1",
		"us-west2":        "us-west1",
		"us-central1":     "us-east1",
		"europe-west1":    "europe-west2",
		"asia-southeast1": "asia-east1",
		// Azure regions
		"eastus":    "eastus2",
		"eastus2":   "eastus",
		"westus":    "westus2",
		"westus2":   "westus",
		"japaneast": "japanwest",
		"japanwest": "japaneast",
	}

	if secondary, ok := regionPairs[primaryRegion]; ok {
		return secondary
	}
	return ""
}
