package dag

import (
	"fmt"

	"github.com/tidbcloud/fastflow/pkg/entity"

	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/service/workflow/action"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

const (
	DisableSourceTidbGroupDNSTaskId                = "disable_source_tidb_group_dns"
	DisableTargetTidbGroupDNSTaskId                = "disable_target_tidb_group_dns"
	PollUntilSourceTidbGroupAvailableTaskId        = "poll_until_source_tidb_group_available"
	PollUntilTargetTidbGroupAvailableTaskId        = "poll_until_target_tidb_group_available"
	DeleteTidbGroupPrivateLinkServiceTaskId        = "delete_tidb_group_private_link_service"
	SetTargetTidbGroupDNSAndEnableTaskId           = "set_target_tidb_group_dns_and_enable"
	EnableSourceTidbGroupDNSTaskId                 = "enable_source_tidb_group_dns "
	CutoverPrivateLinkServiceTaskId                = "cutover_private_link_service"
	CreateTidbGroupPrivateLinkServiceTaskId        = "create_tidb_group_private_link_service"
	PollPrivateLinkServiceMigrationAvailableTaskId = "poll_private_link_service_migration_available"
	CutoverEndpointMetaTaskId                      = "cutover_endpoint_meta"
)

// CutoverPrivateLinkServiceDag creates a DAG for migrating private link services between TiDB groups.
// This DAG handles the complex process of transferring private link connectivity from a source
// TiDB group to a target TiDB group while maintaining service availability and DNS resolution.
//
// Workflow Overview:
// 1. Prepare target environment by removing existing private link service and disabling DNS
// 2. Prepare source environment by disabling DNS and ensuring availability
// 3. Transfer DNS identity and enable DNS on target
// 4. Perform the actual private link service cutover
// 5. Set new DNS identity and enable DNS on source
// 6. Create private link service on source
//
// The cutover process ensures minimal downtime by coordinating DNS changes and service
// migration in a specific sequence that maintains connectivity throughout the transition.
func CutoverPrivateLinkServiceDag() *entity.Dag {
	// Create a new DAG for cutover private link service migration
	// This DAG orchestrates the complex process of transferring private link services
	// between TiDB groups while maintaining DNS resolution and service availability.
	dag := &entity.Dag{
		BaseInfo: entity.BaseInfo{
			ID: common.CutoverPrivateLinkService,
		},
		Name:   common.CutoverPrivateLinkService,
		Status: entity.DagStatusNormal,
		Vars: map[string]entity.DagVar{
			workflow.KeyTraceId:                     {},
			common.KeyPrivateLinkServiceMigrationId: {},
			common.KeySourceClusterId:               {},
			common.KeySourceTidbGroupId:             {},
			common.KeyTargetClusterId:               {},
			common.KeyTargetTidbGroupId:             {},
			common.KeyDNSIdentity:                   {},
			common.KeyNewDNSIdentity:                {},
			common.KeyNewPrivateLinkServiceId:       {},
		},
		Tasks: []entity.Task{
			{
				ID:         DisableSourceTidbGroupDNSTaskId,
				ActionName: action.DisableTidbGroupDNS,
				Params: map[string]any{
					common.KeyClusterId:   fmt.Sprintf("{{%s}}", common.KeySourceClusterId),
					common.KeyTidbGroupId: fmt.Sprintf("{{%s}}", common.KeySourceTidbGroupId),
				},
				DependOn: []string{},
			},
			{
				ID:         PollUntilSourceTidbGroupAvailableTaskId,
				ActionName: action.PollUntilTidbGroupAvailable,
				Params: map[string]any{
					common.KeyClusterId:   fmt.Sprintf("{{%s}}", common.KeySourceClusterId),
					common.KeyTidbGroupId: fmt.Sprintf("{{%s}}", common.KeySourceTidbGroupId),
				},
				DependOn: []string{DisableSourceTidbGroupDNSTaskId},
			},
			{
				ID:         DeleteTidbGroupPrivateLinkServiceTaskId,
				ActionName: action.DeleteTidbGroupPrivateLinkService,
				Params: map[string]any{
					common.KeyClusterId:   fmt.Sprintf("{{%s}}", common.KeyTargetClusterId),
					common.KeyTidbGroupId: fmt.Sprintf("{{%s}}", common.KeyTargetTidbGroupId),
				},
			},
			{
				ID:         DisableTargetTidbGroupDNSTaskId,
				ActionName: action.DisableTidbGroupDNS,
				Params: map[string]any{
					common.KeyClusterId:   fmt.Sprintf("{{%s}}", common.KeyTargetClusterId),
					common.KeyTidbGroupId: fmt.Sprintf("{{%s}}", common.KeyTargetTidbGroupId),
				},
				DependOn: []string{DeleteTidbGroupPrivateLinkServiceTaskId},
			},
			{
				ID:         PollUntilTargetTidbGroupAvailableTaskId,
				ActionName: action.PollUntilTidbGroupAvailable,
				Params: map[string]any{
					common.KeyClusterId:   fmt.Sprintf("{{%s}}", common.KeyTargetClusterId),
					common.KeyTidbGroupId: fmt.Sprintf("{{%s}}", common.KeyTargetTidbGroupId),
				},
				DependOn: []string{DisableTargetTidbGroupDNSTaskId},
			},
			{
				ID:         SetTargetTidbGroupDNSAndEnableTaskId,
				ActionName: action.SetTidbGroupDNSAndEnable,
				Params: map[string]any{
					common.KeyClusterId:   fmt.Sprintf("{{%s}}", common.KeyTargetClusterId),
					common.KeyTidbGroupId: fmt.Sprintf("{{%s}}", common.KeyTargetTidbGroupId),
					common.KeyDNSIdentity: fmt.Sprintf("{{%s}}", common.KeyDNSIdentity),
				},
				DependOn: []string{PollUntilSourceTidbGroupAvailableTaskId, PollUntilTargetTidbGroupAvailableTaskId},
			},
			{
				ID:         CutoverPrivateLinkServiceTaskId,
				ActionName: action.CutoverPrivateLinkService,
				Params: map[string]any{
					common.KeySourceClusterId:               fmt.Sprintf("{{%s}}", common.KeySourceClusterId),
					common.KeySourceTidbGroupId:             fmt.Sprintf("{{%s}}", common.KeySourceTidbGroupId),
					common.KeyTargetClusterId:               fmt.Sprintf("{{%s}}", common.KeyTargetClusterId),
					common.KeyTargetTidbGroupId:             fmt.Sprintf("{{%s}}", common.KeyTargetTidbGroupId),
					common.KeyPrivateLinkServiceMigrationId: fmt.Sprintf("{{%s}}", common.KeyPrivateLinkServiceMigrationId),
				},
				DependOn: []string{SetTargetTidbGroupDNSAndEnableTaskId},
			},
			{
				ID:         PollPrivateLinkServiceMigrationAvailableTaskId,
				ActionName: action.PollPrivateLinkServiceMigrationAvailable,
				Params: map[string]any{
					common.KeySourceClusterId:               fmt.Sprintf("{{%s}}", common.KeySourceClusterId),
					common.KeySourceTidbGroupId:             fmt.Sprintf("{{%s}}", common.KeySourceTidbGroupId),
					common.KeyTargetClusterId:               fmt.Sprintf("{{%s}}", common.KeyTargetClusterId),
					common.KeyTargetTidbGroupId:             fmt.Sprintf("{{%s}}", common.KeyTargetTidbGroupId),
					common.KeyPrivateLinkServiceMigrationId: fmt.Sprintf("{{%s}}", common.KeyPrivateLinkServiceMigrationId),
				},
				DependOn: []string{CutoverPrivateLinkServiceTaskId},
			},
			{
				ID:         CutoverEndpointMetaTaskId,
				ActionName: action.CutoverEndpointMeta,
				Params: map[string]any{
					common.KeySourceClusterId:               fmt.Sprintf("{{%s}}", common.KeySourceClusterId),
					common.KeySourceTidbGroupId:             fmt.Sprintf("{{%s}}", common.KeySourceTidbGroupId),
					common.KeyTargetClusterId:               fmt.Sprintf("{{%s}}", common.KeyTargetClusterId),
					common.KeyTargetTidbGroupId:             fmt.Sprintf("{{%s}}", common.KeyTargetTidbGroupId),
					common.KeyPrivateLinkServiceMigrationId: fmt.Sprintf("{{%s}}", common.KeyPrivateLinkServiceMigrationId),
				},
				DependOn: []string{PollPrivateLinkServiceMigrationAvailableTaskId},
			},
			{
				ID:         EnableSourceTidbGroupDNSTaskId,
				ActionName: action.SetTidbGroupDNSAndEnable,
				Params: map[string]any{
					common.KeyClusterId:   fmt.Sprintf("{{%s}}", common.KeySourceClusterId),
					common.KeyTidbGroupId: fmt.Sprintf("{{%s}}", common.KeySourceTidbGroupId),
					// use new dns identity after cutover
					common.KeyDNSIdentity: fmt.Sprintf("{{%s}}", common.KeyNewDNSIdentity),
				},
				DependOn: []string{PollPrivateLinkServiceMigrationAvailableTaskId},
			},
			{
				ID:         CreateTidbGroupPrivateLinkServiceTaskId,
				ActionName: action.CreateTidbGroupPrivateLinkService,
				Params: map[string]any{
					common.KeyClusterId:               fmt.Sprintf("{{%s}}", common.KeySourceClusterId),
					common.KeyTidbGroupId:             fmt.Sprintf("{{%s}}", common.KeySourceTidbGroupId),
					common.KeyNewPrivateLinkServiceId: fmt.Sprintf("{{%s}}", common.KeyNewPrivateLinkServiceId),
				},
				DependOn: []string{EnableSourceTidbGroupDNSTaskId},
			},
		},
	}

	return dag
}
