package action

import (
	"fmt"
	"time"

	dplanemgrv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"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/utils"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

type PreCreateSharedPoolAction struct {
	dataplaneManager dataplane.Manager
	client           dplanemgrv1.DataPlaneServiceClient
}

const PreCreateSharedPoolActionName = "pre-create-shared-pool"

func NewPreCreateSharedPoolAction(
	dataplaneManager dataplane.Manager,
	client dplanemgrv1.DataPlaneServiceClient,
) actions.Action {
	return &PreCreateSharedPoolAction{
		dataplaneManager: dataplaneManager,
		client:           client,
	}
}

func (a *PreCreateSharedPoolAction) Name() string {
	return PreCreateSharedPoolActionName
}

func (a *PreCreateSharedPoolAction) Invoke(args actions.ActionArgs) error {
	// generate context
	ctx := utils.GenerateContext(args)
	tilog.Info(ctx, "pre create sharedPool action invoked")

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

	dataplaneInfo, err := a.client.GetDataPlane(ctx, &dplanemgrv1.GetDataPlaneRequest{
		DataPlaneId: dataplaneId,
	})

	if err != nil {
		tilog.Error(ctx, "failed to get dataplane", zap.Error(err))
		return fmt.Errorf("failed to get dataplane: %w", err)
	}

	if dataplaneInfo.Status != dplanemgrv1.DataPlane_Active {
		tilog.Error(ctx, "dataplane is not ready", zap.String("dataplaneId", dataplaneId), zap.String("status", string(dataplaneInfo.Status)))

		// If the dataplane is not ready, we should not proceed with creating the shared pool.
		// This is to ensure that the shared pool is created only when the dataplane is in an active state.

		// Optional: wait a bit before returning an error
		// TODO: remove this sleep in production code
		time.Sleep(20 * time.Second)

		return fmt.Errorf("dataplane %s is not ready, current status: %s", dataplaneId, dataplaneInfo.Status)
	}

	return nil
}
