package render

import (
	"fmt"
)

// TemplateLibrary holds named templates and renders them with variable substitution.
type TemplateLibrary struct {
	templates map[string]string
	render    *templateRender
}

// NewTemplateLibrary creates a TemplateLibrary with the default rendering pipeline.
func NewTemplateLibrary() *TemplateLibrary {
	r := newTemplateRender()
	r.registerRender(newRemoveUnexistedArgBlockRender())
	r.registerRender(newReplaceArgByValRender())
	r.registerRender(newUnfoldTemplateRender())
	return &TemplateLibrary{
		templates: make(map[string]string),
		render:    r,
	}
}

// SafeNewTemplate registers a named template, panicking on duplicate names.
func (tl *TemplateLibrary) SafeNewTemplate(name, template string) {
	if _, ok := tl.templates[name]; ok {
		panic(fmt.Sprintf("TemplateLibrary.SafeNewTemplate: template `%s` already existed", name))
	}
	// check loop-referring by a pre-render call; if a loop exists it will crash
	_ = tl.render.doRender(template, map[string]string{})
	tl.templates[name] = template
}

// Render renders a named template with the given args.
func (tl *TemplateLibrary) Render(name string, args map[string]string) (rendered string, err error) {
	template, ok := tl.templates[name]
	if !ok {
		return "", fmt.Errorf("TemplateLibrary.Render: template `%s` not found", name)
	}
	rendered = tl.render.doRender(template, args)
	return rendered, nil
}

// defaultRender is a package-level render pipeline used by the standalone RenderContent function.
var defaultRender = func() *templateRender {
	r := newTemplateRender()
	r.registerRender(newRemoveUnexistedArgBlockRender())
	r.registerRender(newReplaceArgByValRender())
	r.registerRender(newUnfoldTemplateRender())
	return r
}()

// RenderContent performs variable substitution on the given content using the provided args.
// This is a standalone function that does not require a TemplateLibrary instance.
func RenderContent(content string, args map[string]string) string {
	return defaultRender.doRender(content, args)
}

// NewMockYamlTemplate returns a fake YAML template for testing.
func NewMockYamlTemplate(purpose string) string {
	return fmt.Sprintf(
		"# this is a fake yaml file\n# for %s\n# this yaml file is a template",
		purpose)
}
