// Package h provides a Go-native DSL for HTML composition.
// Every element, attribute, and text node is constructed as a function that returns a [h.H] DOM node.
//
// Example:
//
//	h.Div(
//		h.H1(h.Text("Hello, Via")),
//		h.P(h.Text("Pure Go. No tmplates.")),
//	)
package h

import (
	"io"

	g "maragu.dev/gomponents"
	gc "maragu.dev/gomponents/components"
)

// H represents a DOM node.
type H interface {
	Render(w io.Writer) error
}

// Text creates a text DOM node that Renders the escaped string t.
func Text(t string) H {
	return g.Text(t)
}

// Textf creates a text DOM node that Renders the interpolated and escaped string format.
func Textf(format string, a ...any) H {
	return g.Textf(format, a...)
}

// Raw creates a text DOM [Node] that just Renders the unescaped string t.
func Raw(s string) H {
	return g.Raw(s)
}

// Rawf creates a text DOM [Node] that just Renders the interpolated and
// unescaped string format.
func Rawf(format string, a ...any) H {
	return g.Rawf(format, a...)
}

// Attr creates an attribute DOM [Node] with a name and optional value.
// If only a name is passed, it's a name-only (boolean) attribute (like "required").
// If a name and value are passed, it's a name-value attribute (like `class="header"`).
// More than one value make [Attr] panic.
// Use this if no convenience creator exists in the h package.
func Attr(name string, value ...string) H {
	return g.Attr(name, value...)
}

func If(condition bool, n H) H {
	if condition {
		return n
	}
	return nil
}

// HTML5Props defines properties for HTML5 pages. Title is set always set, Description
// and Language elements only if the strings are non-empty.
type HTML5Props struct {
	Title       string
	Description string
	Language    string
	Head        []H
	Body        []H
	HTMLAttrs   []H
}

// HTML5 document template.
func HTML5(p HTML5Props) H {
	gp := gc.HTML5Props{
		Title:       p.Title,
		Description: p.Description,
		Language:    p.Language,
		Head:        retype(p.Head),
		Body:        retype(p.Body),
		HTMLAttrs:   retype(p.HTMLAttrs),
	}
	gp.Head = append(gp.Head, Script(Type("module"), Src("/_datastar.js")))
	return gc.HTML5(gp)
}

// JoinAttrs with the given name only on the first level of the given nodes. This means that
// attributes on non-direct descendants are ignored. Attribute values are joined by spaces.
//
// Note that this renders all first-level attributes to check whether they should be processed.
func JoinAttrs(name string, children ...H) H {
	return gc.JoinAttrs(name, retype(children)...)
}
