package templating

import (
	"html/template"
	"reflect"

	"golang.org/x/exp/slices"
)

// Parsed represents a parsed template that takes as argument a context of type C.
type Parsed[C any] struct {
	// does the context type an embed of the runtime flags type?
	hasRuntimeFlagsEmbed bool

	tpl   *template.Template // parsed template
	funcs []FlagFunc         // optionally concfigured functions.
}

// Parse parses a template with the given name and source.
// If base is not nil, every template associated with the base template is copied into the given template.
// Functions will be applied on creation time to represent the context for the given template.
func Parse[C any](name string, source []byte, base *template.Template, funcs ...FlagFunc) Parsed[C] {
	tp := reflect.TypeFor[C]()

	// determine if we have an embedded field in the struct
	var hasEmbed bool
	if tp.Kind() == reflect.Struct {
		field, ok := tp.FieldByName(runtimeFlagsName)
		if ok {
			hasEmbed = field.Anonymous
		}
	}

	// create a new template, and optionally inherit from the base template
	new := template.New(name)
	if base != nil {
		for _, tree := range base.Templates() {
			root := tree.Tree.Copy()
			new.AddParseTree(tree.Name(), root)
		}
	}

	return Parsed[C]{
		hasRuntimeFlagsEmbed: hasEmbed,
		tpl:                  template.Must(new.Parse(string(source))),
		funcs:                funcs,
	}
}

// Prepare prepares this template to be used with the given templating.
func (p *Parsed[C]) Prepare(templating *Templating, funcs ...FlagFunc) *Template[C] {
	pcopy := *p // make a copy of p!

	wrap := Template[C]{
		templating: templating,

		p: &pcopy,
	}

	// copy the functions!
	pcopy.funcs = slices.Clone(pcopy.funcs)
	pcopy.funcs = append(wrap.p.funcs, funcs...)

	return &wrap
}
