package deploy

import (
	"context"
)

type ClusterMeta struct {
	Agent          string
	K8sClusterName string
	BizType        string
	TenantID       string
	ApplicationID  string
}

// Task represents a unit of work in the deployment lifecycle.
// It encapsulates the logic for creating and deleting resources, along with
// associated metadata for observability.
//
// The lifecycle of a Task is managed by the Deployer:
//   - Deploy: Create -> PostCreate
//   - Destroy: Delete -> PostDelete
//
// Note that "Post" methods (PostCreate, PostDelete) are only executed if the
// primary method (Create, Delete) returns Done or Error.
// If the primary method returns Panic, the post action is skipped.
type Task interface {
	// Name returns the name of the task, which is used for logging and metrics.
	Name() string

	// ClusterMeta returns the metadata of the cluster associated with the task.
	ClusterMeta() ClusterMeta

	// Create executes the main logic for creating resources.
	Create(context.Context) Result

	// PostCreate executes the logic after creation, often used for status updates or hooks.
	PostCreate(context.Context) Result

	// Delete executes the main logic for deleting resources.
	Delete(context.Context) Result

	// PostDelete executes the logic after deletion.
	PostDelete(context.Context) Result
}

type CreateSuccessHook func(ctx context.Context, task Task)

type TaskWrapper struct {
	Task
	hook CreateSuccessHook

	createResult Result
}

func NewTaskWrapper(task Task, hook CreateSuccessHook) *TaskWrapper {
	return &TaskWrapper{
		Task: task,
		hook: hook,
	}
}

var _ Task = &TaskWrapper{}

func (t *TaskWrapper) Create(ctx context.Context) Result {
	res := t.Task.Create(ctx)
	t.createResult = res
	return res
}

func (t *TaskWrapper) PostCreate(ctx context.Context) Result {
	res := t.Task.PostCreate(ctx)

	// ref `MinRequeue` about "how is truly error"
	if t.createResult.err != nil && !RequeueOnly(t.createResult.err) {
		return res
	}

	if res.err != nil && !RequeueOnly(res.err) {
		return res
	}

	t.hook(ctx, t.Task)
	return res
}
