/**
 * **Not a sanitizer.** This module extracts visible text from an HTML (or
 * plain-text) string for excerpt rendering. The safety invariant is: the
 * OUTPUT must only ever be rendered via Svelte text interpolation — never
 * `{@html}`. The DOMParser document is inert (scripts don't execute), but
 * the returned string is whatever text the input carried.
 *
 * Note on inputs: STORY bodies are additionally sanitised against the OWASP
 * allow-list on the server; JOURNEY intros are stored VERBATIM (unsanitised
 * by design — see GeschichteService.bodyForType) and arrive here untrusted.
 *
 * Do not use these helpers to defend against XSS — `safeHtml()` in
 * `./sanitize.ts` is the only sanitiser. Calling `extractText()` on
 * untrusted input does not protect against `javascript:` URLs,
 * event-handler attributes, or `<svg/onload>` payloads.
 */

/**
 * Strip tags and return plain text. Uses DOMParser in the browser; on the
 * server it falls back to a regex that drops angle-bracket sequences.
 * The fallback is **not** a sanitiser — see module docstring.
 */
export function extractText(html: string | null | undefined): string {
	if (!html) return '';
	if (typeof DOMParser === 'function') {
		const doc = new DOMParser().parseFromString(html, 'text/html');
		return (doc.body.textContent ?? '').replace(/\s+/g, ' ').trim();
	}
	return html
		.replace(/<[^>]*>/g, '')
		.replace(/\s+/g, ' ')
		.trim();
}

/**
 * Strip tags then truncate to `max` chars on a word boundary, appending an
 * ellipsis when truncated. Used for editorial story excerpts.
 */
export function plainExcerpt(html: string | null | undefined, max = 80): string {
	const text = extractText(html);
	if (text.length <= max) return text;
	return text.slice(0, max).replace(/\s+\S*$/, '') + '…';
}
