package action

import (
	"fmt"

	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow"
	"github.com/tidbcloud/cluster-service-ng/pkg/dataplane"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/actions"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/repo"
	templateversion "github.com/tidbcloud/cluster-service-ng/pkg/template/version"
	"github.com/tidbcloud/cluster-service-ng/pkg/utils"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

type ApplyDefaultSvcAction struct {
	dataplaneManager   dataplane.Manager
	sharedPoolRepo     repo.SharedPoolRepo
	templateVersionSvc *templateversion.Service
}

const ApplyDefaultSvcActionName = "apply-default-svc"

func (a *ApplyDefaultSvcAction) Name() string {
	return ApplyDefaultSvcActionName
}

func NewApplyDefaultSvcAction(
	sharedPoolRepo repo.SharedPoolRepo,
	dataplaneManager dataplane.Manager,
	templateVersionSvc *templateversion.Service,
) actions.Action {
	return &ApplyDefaultSvcAction{
		sharedPoolRepo:     sharedPoolRepo,
		dataplaneManager:   dataplaneManager,
		templateVersionSvc: templateVersionSvc,
	}
}

func (a *ApplyDefaultSvcAction) Invoke(args actions.ActionArgs) error {
	// generate context
	ctx := utils.GenerateContext(args)
	tilog.Info(ctx, "apply default tidb svc comp invoked")

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

	for _, comp := range sharedPool.GetComponentGroups() {
		if comp.GetComponentType() != apiv1.ComponentType_PD {
			continue
		}

		// render template
		templArgs := map[string]string{
			"ClusterId":      sharedPool.GetId(),
			"ComponentGroup": entity.GetComponentGroupName(comp),
		}

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

		err = templateExecuteWithVersionResolver(ctx, remoteCli, "default_pd_svc", "", templArgs, false, a.templateVersionSvc)
		if err != nil {
			tilog.Error(ctx, "failed to apply default pd svc", zap.String("cluster", sharedPool.GetId()), zap.String("component id", comp.GetId()), zap.Error(err))
			return fmt.Errorf("failed to apply default pd svc: %w", err)
		}
		tilog.Info(ctx, "apply default pd svc successfully", zap.String("cluster", sharedPool.GetId()), zap.String("component id", comp.GetId()))
		break
	}

	return nil
}
