// see: https://andyburke.dev/andyburke/serverus/src/branch/dev/handlers/markdown.ts

/* MARKDOWN TO HTML */

/* order of these transforms matters, so we list them here in an array and build type from it after. */
const MD_TRANSFORM_NAMES = [
	"characters",
	"headings",
	"horizontal_rules",
	"list_items",
	"bold",
	"italic",
	"strikethrough",
	"code",
	"images",
	"links",
	"breaks",
];
const MD_TRANSFORMS = {
	characters: [
		[/&/g, "&amp;"],
		[/</g, "&lt;"],
		[/>/g, "&gt;"],
		[/"/g, "&quot;"],
		[/'/g, "&#39;"],
	],

	headings: [
		[/^#\s(.+)$/gm, "<h1>$1</h1>\n"],
		[/^##\s(.+)$/gm, "<h2>$1</h2>\n"],
		[/^###\s(.+)$/gm, "<h3>$1</h3>\n"],
		[/^####\s(.+)$/gm, "<h4>$1</h4>\n"],
		[/^#####\s(.+)$/gm, "<h5>$1</h5>\n"],
	],

	horizontal_rules: [[/^----*$/gm, "<hr>\n"]],

	list_items: [
		[/\n\n([ \t]*)([-\*\.].*?)\n\n/gs, "\n\n<ul>\n$1$2\n</ul>\n\n\n"],
		[/^([ \t]*)[-\*\.](\s+.*)$/gm, "<li>$1$2</li>\n"],
	],

	bold: [[/\*([^\*]+)\*/gm, "<strong>$1</strong>"]],

	italic: [[/_([^_]+)_/gm, "<i>$1</i>"]],

	strikethrough: [[/~([^~]+)~/gm, "<s>$1</s>"]],

	code: [
		[/```\n([^`]+)\n```/gm, "<pre><code>$1</code></pre>"],
		[/```([^`]+)```/gm, "<code>$1</code>"],
	],

	images: [[/!\[([^\]]+)\]\(([^\)]+)\)/g, '<img src="$2" alt="$1">']],

	links: [[/\[([^\]]+)\]\(([^\)]+)\)/g, '<a href="$2">$1</a>']],

	breaks: [
		[/\s\s\n/g, "\n<br>\n"],
		[/\n\n/g, "\n<br>\n"],
	],
};

/**
 * Convert markdown to HTML.
 * @param markdown The markdown string.
 * @param options _(Optional)_ A record of transforms to disable.
 * @returns The generated HTML string.
 */
function md_to_html(markdown, transform_config) {
	let html = markdown ?? "";
	for (const transform_name of MD_TRANSFORM_NAMES) {
		const enabled =
			typeof transform_config === "undefined" || transform_config[transform_name] !== false;
		if (!enabled) {
			continue;
		}

		const transforms = MD_TRANSFORMS[transform_name] ?? [];
		for (const markdown_transformer of transforms) {
			html = html.replace(...markdown_transformer);
		}
	}

	return `<div class="html-from-markdown">${html}</div>`;
}
