package operate

import (
	"bytes"
	"text/template"

	v1 "github.com/tidbcloud/infra-component/api/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
)

var scheme = runtime.NewScheme()

func init() {
	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
	utilruntime.Must(v1.AddToScheme(scheme))
}

// RenderComponent renders the template of the objects of the given component with the
// given options. The rendered template are later converted to Kubernetes objects that
// are known to the runtime scheme.
func RenderComponent(c v1.Component, options interface{}) ([]runtime.Object, error) {
	var result []runtime.Object
	for _, obj := range c.Spec.Objects {
		rendered, err := renderObject(obj, options)
		if err != nil {
			return nil, err
		}
		result = append(result, rendered)
	}
	return result, nil
}

func renderObject(obj v1.ComponentObject, options interface{}) (runtime.Object, error) {
	tmpl, err := template.New(obj.Name).Parse(obj.Template)
	if err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, options); err != nil {
		return nil, err
	}
	decoder := serializer.NewCodecFactory(scheme).UniversalDeserializer()
	object, _, err := decoder.Decode(buf.Bytes(), nil, nil)
	if err != nil {
		return nil, err
	}
	return object, nil
}
