/**
 * Tiny DOM builder. ALL text and attribute values are set via `textContent` / `setAttribute` — this
 * module NEVER assigns `innerHTML`, so untrusted server/host data (host subdomains, etc.) can never
 * inject markup. Children passed as strings become text nodes (also safe).
 */
export type Child = Node | string

export interface ElProps {
  class?: string
  text?: string
  type?: string
  name?: string
  placeholder?: string
  value?: string
  disabled?: boolean
  autocomplete?: string
  title?: string
  src?: string
  alt?: string
  role?: string
  ariaLabel?: string
  onClick?: (e: MouseEvent) => void
  onSubmit?: (e: SubmitEvent) => void
}

export function el<K extends keyof HTMLElementTagNameMap>(
  tag: K,
  props: ElProps = {},
  children: Child[] = [],
): HTMLElementTagNameMap[K] {
  const node = document.createElement(tag)
  if (props.class !== undefined) node.className = props.class
  if (props.text !== undefined) node.textContent = props.text
  if (props.type !== undefined) node.setAttribute('type', props.type)
  if (props.name !== undefined) node.setAttribute('name', props.name)
  if (props.placeholder !== undefined) node.setAttribute('placeholder', props.placeholder)
  if (props.value !== undefined) (node as HTMLInputElement).value = props.value
  if (props.disabled) node.setAttribute('disabled', 'true')
  if (props.autocomplete !== undefined) node.setAttribute('autocomplete', props.autocomplete)
  if (props.title !== undefined) node.setAttribute('title', props.title)
  if (props.src !== undefined) node.setAttribute('src', props.src)
  if (props.alt !== undefined) node.setAttribute('alt', props.alt)
  if (props.role !== undefined) node.setAttribute('role', props.role)
  if (props.ariaLabel !== undefined) node.setAttribute('aria-label', props.ariaLabel)
  if (props.onClick !== undefined) node.addEventListener('click', props.onClick as EventListener)
  if (props.onSubmit !== undefined) node.addEventListener('submit', props.onSubmit as EventListener)
  for (const child of children) node.append(child)
  return node
}

/** Remove all children of a node. */
export function clear(node: Element): void {
  while (node.firstChild) node.removeChild(node.firstChild)
}

/** Replace a node's content with a single new child. */
export function mount(root: Element, child: Node): void {
  clear(root)
  root.append(child)
}
