package k8s

import (
	"encoding/json"
	"time"

	"github.com/crossplane/crossplane-runtime/pkg/meta"
	"gomodules.xyz/jsonpatch/v2"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
	pingcapDeletionTrigger = "pingcap.com/deletion-trigger"
)

type ObjectPatch = func(client.Object) *jsonpatch.Operation

var RemoveCrossplaneExternalCreatePending ObjectPatch = func(obj client.Object) *jsonpatch.Operation {
	if obj.GetAnnotations() == nil || obj.GetAnnotations()[meta.AnnotationKeyExternalCreatePending] == "" {
		return nil
	}
	return &jsonpatch.Operation{
		Operation: "remove",
		Path:      "/metadata/annotations/crossplane.io~1external-create-pending",
	}
}

var DeletionTrigger ObjectPatch = func(obj client.Object) *jsonpatch.Operation {
	annotations, op := obj.GetAnnotations(), "replace"
	if annotations == nil || annotations[pingcapDeletionTrigger] == "" {
		op = "add"
	}
	return &jsonpatch.Operation{
		Operation: op,
		Path:      "/metadata/annotations/pingcap.com~1deletion-trigger",
		Value:     time.Now().Format(time.RFC3339),
	}
}

func ConstructPatch(patchPtrs ...*jsonpatch.Operation) (client.Patch, error) {
	patches := make([]jsonpatch.Operation, 0, len(patchPtrs))
	for _, patchPtr := range patchPtrs {
		if patchPtr != nil {
			patches = append(patches, *patchPtr)
		}
	}
	buf, err := json.Marshal(patches)
	if err != nil {
		return nil, err
	}
	return client.RawPatch(types.JSONPatchType, buf), nil
}

var CordonNode ObjectPatch = func(obj client.Object) *jsonpatch.Operation {
	return &jsonpatch.Operation{
		Operation: "replace",
		Path:      "/spec/unschedulable",
		Value:     true,
	}
}

var UncordonNode ObjectPatch = func(obj client.Object) *jsonpatch.Operation {
	return &jsonpatch.Operation{
		Operation: "replace",
		Path:      "/spec/unschedulable",
		Value:     false,
	}
}
