package agentbuild

import (
	"context"
	"fmt"
	"time"

	"github.com/crossplane/crossplane-runtime/pkg/meta"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

// externalCreateStalledAfter is how long the external-create-pending annotation
// must remain the newest tracking annotation before the creation is considered
// stalled. Crossplane stamps the annotation right before each provider create
// call and supersedes it with failed/succeeded once the call returns, so a
// pending annotation older than any plausible in-flight call has nothing left
// to wait for.
const externalCreateStalledAfter = 10 * time.Minute

// ClearStalledExternalCreate removes crossplane's external-create-pending
// annotation from a managed resource whose external creation appears to have
// stalled, so crossplane resumes reconciling it. It reports whether the
// annotation was cleared.
//
// Crossplane refuses to reconcile a managed resource whose creation result is
// unknown (the pending annotation is newer than the failed/succeeded ones)
// until the annotation is removed manually. Automating this is safe for node
// pool managed resources because their name equals the external name: once
// cleared, crossplane either observes the existing node pool or its create
// retry collides by name, never producing a duplicate.
func ClearStalledExternalCreate(ctx context.Context, cli client.Client, obj client.Object) (bool, error) {
	err := cli.Get(ctx, client.ObjectKeyFromObject(obj), obj)
	if client.IgnoreNotFound(err) != nil {
		return false, fmt.Errorf("failed to get %s: %w", obj.GetName(), err)
	}
	if err != nil {
		return false, nil
	}
	if !meta.ExternalCreateIncomplete(obj) {
		return false, nil
	}
	if time.Since(meta.GetExternalCreatePending(obj)) < externalCreateStalledAfter {
		return false, nil
	}
	meta.RemoveAnnotations(obj, meta.AnnotationKeyExternalCreatePending)
	if err := cli.Update(ctx, obj); err != nil {
		return false, fmt.Errorf("failed to update %s: %w", obj.GetName(), err)
	}
	return true, nil
}
