const VOID_ELEMENTS = new Set([
  "area", "base", "br", "col", "embed", "hr", "img", "input",
  "link", "meta", "param", "source", "track", "wbr",
]);

const ATTR_MAP: Record<string, string> = {
  className: "class",
  htmlFor: "for",
};

function escapeAttr(s: string): string {
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
}

function flatten(children: any[]): string {
  return children
    .flat(Infinity)
    .filter((c) => c != null && c !== false && c !== true)
    .map((c) => String(c))
    .join("");
}

export function h(
  tag: string | ((props: any) => string),
  props: Record<string, any> | null,
  ...children: any[]
): string {
  if (typeof tag === "function") {
    return tag({ ...props, children: children.length === 1 ? children[0] : children });
  }

  let attrs = "";
  let innerHTML = "";

  if (props) {
    for (const [key, value] of Object.entries(props)) {
      if (key === "children") continue;
      if (key === "dangerouslySetInnerHTML") {
        innerHTML = value.__html;
        continue;
      }
      if (value == null || value === false) continue;
      const name = ATTR_MAP[key] || key;
      if (value === true) {
        attrs += ` ${name}`;
      } else {
        attrs += ` ${name}="${escapeAttr(String(value))}"`;
      }
    }
  }

  if (VOID_ELEMENTS.has(tag)) {
    return `<${tag}${attrs}>`;
  }

  const content = innerHTML || flatten(children);
  return `<${tag}${attrs}>${content}</${tag}>`;
}

export function Fragment({ children }: { children: any }): string {
  return Array.isArray(children) ? flatten(children) : String(children ?? "");
}
