package action

import (
	"fmt"

	"github.com/tidbcloud/cluster-service-ng/domain/workflow"
	"github.com/tidbcloud/cluster-service-ng/pkg/clusterconfig"
	"github.com/tidbcloud/cluster-service-ng/pkg/dataplane"
	"github.com/tidbcloud/cluster-service-ng/pkg/k8s"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/actions"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/repo"
	"github.com/tidbcloud/cluster-service-ng/pkg/utils"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type CreateTiDBSemConfigAction struct {
	dataplaneManager    dataplane.Manager
	sharedPoolRepo      repo.SharedPoolRepo
	clusterConfigClient clusterconfig.Client
}

const (
	CreateTiDBSemConfigActionName = "create-tidb-sem-config"

	semConfigMapName = "db-tidb-sem-config"
)

func (a *CreateTiDBSemConfigAction) Name() string {
	return CreateTiDBSemConfigActionName
}

// CreateTiDBSemConfigAction creates and applies TiDB SEM configuration
func NewCreateTiDBSemConfigAction(
	sharedPoolRepo repo.SharedPoolRepo,
	dataplaneManager dataplane.Manager,
	clusterConfigClient clusterconfig.Client,
) actions.Action {
	return &CreateTiDBSemConfigAction{
		sharedPoolRepo:      sharedPoolRepo,
		dataplaneManager:    dataplaneManager,
		clusterConfigClient: clusterConfigClient,
	}
}

func (a *CreateTiDBSemConfigAction) Invoke(args actions.ActionArgs) error {
	// generate context
	ctx := utils.GenerateContext(args)
	tilog.Info(ctx, "begin to create tidb sem config")

	sharedPoolId, err := args.GetString(workflow.SharedPoolIdKey)
	if err != nil {
		return fmt.Errorf("failed to get sharedPool id: %w", err)
	}

	// load sharedPool
	sharedPool, err := a.sharedPoolRepo.Load(ctx, sharedPoolId, false)
	if err != nil {
		return fmt.Errorf("failed to load sharedPool: %w", err)
	}

	// get tidb sem config
	TiDBSemConfig, err := a.clusterConfigClient.GetClusterTiDBSemConfig(ctx, sharedPoolId)
	if err != nil {
		return fmt.Errorf("failed to get tidb sem config: %w", err)
	}

	// get remote client
	remoteCli, err := a.dataplaneManager.GetClient(sharedPool.GetDataplaneName())
	if err != nil {
		tilog.Error(ctx, "failed to get remote client for shared pool", zap.String("dataplaneName", sharedPool.GetDataplaneName()), zap.Error(err))
		return fmt.Errorf("failed to get remote client for shared pool: %w", err)
	}

	cm := &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      semConfigMapName,
			Namespace: sharedPool.GetDataPlaneNamespace(),
		},
		Data: map[string]string{
			"sem.json": TiDBSemConfig,
		},
	}
	if err := k8s.CreateIfNotExist(ctx, remoteCli, cm); err != nil {
		tilog.Error(ctx, "failed to create tidb sem configmap", zap.String("configmapName", semConfigMapName), zap.String("namespace", sharedPool.GetDataPlaneNamespace()), zap.Error(err))
		return err
	}

	return nil
}
