package workflows

import (
	"fmt"
	"time"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/consts"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
	// defaultTTL is 7 days
	defaultTTL = &metav1.Duration{Duration: 7 * 24 * time.Hour}
)

func NewEnableTiProxy(cluster *cloudv1.Cluster, groupID, wfNameSuffix string) *cloudv1.Workflow {
	wf := &cloudv1.Workflow{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: cluster.Namespace,
			Name:      fmt.Sprintf("%s-%s", consts.WorkflowTypeEnableTiProxy, wfNameSuffix),
			Labels:    buildLabels(consts.WorkflowTypeEnableTiProxy, cluster, groupID),
		},
		Spec: cloudv1.WorkflowSpec{
			Type: consts.WorkflowTypeEnableTiProxy,
			TTL:  defaultTTL,
			Steps: cloudv1.WorkflowSteps{
				{
					Name: "Wait tiproxy to be ready",
					Uses: consts.WorkflowActionWaitClusterSynced,
					Inputs: cloudv1.InputsWrapper{
						Object: map[string]interface{}{
							"name":      cluster.Name,
							"namespace": cluster.Namespace,
						},
					},
				},
				{
					Name: "Use TiProxy as LB target",
					Uses: consts.WorkflowActionToggleLBTarget,
					Inputs: cloudv1.InputsWrapper{
						Object: map[string]interface{}{
							"name":       cluster.Name,
							"namespace":  cluster.Namespace,
							"groupId":    groupID,
							"useTiProxy": true,
						},
					},
				},
				// TODO(ideascf): check k8s service to ensure the LB target is on TiProxy.
				{
					Name: "Wait for LB switching to complete",
					Uses: consts.WorkflowActionSleep,
					Inputs: cloudv1.InputsWrapper{
						Object: map[string]interface{}{
							"duration": getWaitTimeToggleLBTarget(cluster),
						},
					},
				},
				{
					Name: "Mark LB target on TiProxy",
					Uses: consts.WorkflowActionMutateAnnotations,
					Inputs: cloudv1.InputsWrapper{
						Object: map[string]interface{}{
							"name":      cluster.Name,
							"namespace": cluster.Namespace,
							"type":      "cluster",
							"annotations": map[string]string{
								consts.AnnoKeyLBTargetOnTiProxy(groupID): consts.AnnoValTrue,
							},
						},
					},
				},
				{
					// TODO(ideascf): It's a workaround to ensure the tidb changes are synced to the cluster before we mark this cluster CR as Running.
					Name: "Wait for tidb changes to be synced",
					Uses: consts.WorkflowActionSleep,
					Inputs: cloudv1.InputsWrapper{
						Object: map[string]interface{}{
							"duration": "60s",
						},
					},
				},
				{
					Name: "Mark LB toggle finished",
					Uses: consts.WorkflowActionMutateAnnotations,
					Inputs: cloudv1.InputsWrapper{
						Object: map[string]interface{}{
							"name":      cluster.Name,
							"namespace": cluster.Namespace,
							"type":      "cluster",
							"annotations": map[string]string{
								consts.AnnoKeyTiProxyToggleWorkflow: "-",
							},
						},
					},
				},
			},
		},
	}

	return wf
}

func getWaitTimeToggleLBTarget(cluster *cloudv1.Cluster) string {
	waitTime, ok := cluster.Annotations[consts.AnnoKeyWaitTimeForToggleLBTarget]
	if !ok {
		return consts.DefaultWaitTimeForToggleLBTarget
	}
	return waitTime
}

func buildLabels(tp cloudv1.WorkflowType, cluster *cloudv1.Cluster, groupID string) map[string]string {
	labels := map[string]string{
		cloudv1.LabelServiceType:   cloudv1.ServiceTypeDedicated,
		cloudv1.WorkflowTypeTagKey: string(tp),
		cloudv1.TenantTagKey:       cluster.GetTenantID(),
		cloudv1.ProjectTagKey:      cluster.GetProjectID(),
		cloudv1.ClusterTagKey:      cluster.GetClusterID(),
		cloudv1.GroupTagKey:        groupID,
		cloudv1.ProviderTypeLabel:  cluster.GetProviderType(),
		cloudv1.RegionLabel:        cluster.GetRegion(),
	}
	// use the same reconciler as the cluster
	if reconciler, ok := cluster.Labels[cloudv1.ReconcilerLabelKey]; ok {
		labels[cloudv1.ReconcilerLabelKey] = reconciler
	}

	return labels
}
