package action

import (
	"fmt"
	"time"

	clusteragentv1 "github.com/tidbcloud/cluster-service-ng/api/tidbcloud/cluster-agent/v1"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow"
	"github.com/tidbcloud/cluster-service-ng/pkg/clustergateway"
	"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"
)

const RestartTiDBGroupsActionName = "restart-tidb-groups"

type restartTiDBGroupsAction struct {
	sharedPoolRepo    repo.SharedPoolRepo
	tidbGroupRepo     repo.TiDBGroupRepo
	clustergatewayCli clustergateway.Client
}

func NewRestartTiDBGroupsAction(
	sharedPoolRepo repo.SharedPoolRepo,
	tidbGroupRepo repo.TiDBGroupRepo,
	clustergatewayCli clustergateway.Client,
) actions.Action {
	return actions.CreateActionFromAsync(&restartTiDBGroupsAction{
		sharedPoolRepo:    sharedPoolRepo,
		tidbGroupRepo:     tidbGroupRepo,
		clustergatewayCli: clustergatewayCli,
	}, time.Minute, time.Minute*60)
}

func (a *restartTiDBGroupsAction) Name() string {
	return RestartTiDBGroupsActionName
}

func (a *restartTiDBGroupsAction) Start(args actions.ActionArgs) error {
	ctx := utils.GenerateContext(args)
	tilog.Info(ctx, fmt.Sprintf("start %s action...", a.Name()))

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

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

	// list all tidb groups on the shared pool
	tidbGroups, err := a.tidbGroupRepo.List(ctx, []string{sharedPoolId}, nil, nil, nil, false)
	if err != nil {
		return fmt.Errorf("failed to list tidb groups: %w", err)
	}
	if len(tidbGroups) == 0 {
		tilog.Info(ctx, "no tidb groups found for shared pool, no need to restart", zap.String("sharedPoolId", sharedPoolId))
		return nil
	}

	for _, tidbGroup := range tidbGroups {
		err = a.clustergatewayCli.ClusterAgentOpsRestart(ctx, sharedPool, &clusteragentv1.RestartReq{
			OperationId: fmt.Sprintf("restarttidb%s%s", tidbGroup.GetId(), time.Now().UTC().Format("2006010215")),
			ClusterId:   sharedPoolId,
			TargetType:  clusteragentv1.RestartTargetType_COMPONENT,
			TargetName:  "tidb",
			Force:       false,
			TargetGroup: fmt.Sprintf("db-%s", tidbGroup.GetId()),
		})
		if err != nil {
			tilog.Error(ctx, "failed to restart tidb group", zap.Error(err), zap.String("tidbGroupId", tidbGroup.GetId()))
			return fmt.Errorf("failed to restart tidb group %s: %w", tidbGroup.GetId(), err)
		}
	}

	return nil
}

// CheckFinish returns true immediately — the cluster agent handles the rolling restart asynchronously.
func (a *restartTiDBGroupsAction) CheckFinish(args actions.ActionArgs) (bool, error) {
	return true, nil
}
