/**
 * Server-side HTML renderer for markwhen projections.
 *
 * Shells out to `@markwhen/mw` CLI (same binary the official tool uses)
 * rather than importing the parser directly. Why: the view templates'
 * inlined Vue app was built against `@markwhen/parser@0.10.x`, whose
 * output shape differs from the npm-current `@markwhen/parser@1.x`. The
 * CLI ships its own matched parser, so delegating to it avoids any
 * version-skew silently breaking the render.
 *
 * The binary writes HTML to a destination file, so we round-trip through
 * a per-request temp file pair. ~5ms overhead; cheap vs. the correctness.
 */

import { writeFileSync, readFileSync, unlinkSync, mkdtempSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { createRequire } from 'node:module';
import { spawnSync } from 'node:child_process';

const require_ = createRequire(import.meta.url);
let mwBinPath: string | null = null;

function findMwBinary(): string {
	if (mwBinPath) return mwBinPath;
	const pkgJson = require_.resolve('@markwhen/mw/package.json');
	const pkgDir = pkgJson.slice(0, pkgJson.length - '/package.json'.length);
	mwBinPath = join(pkgDir, 'lib', 'index.js');
	return mwBinPath;
}

export function renderMarkwhenHtml(
	mwText: string,
	view: 'timeline' | 'calendar' = 'timeline',
): string {
	if (!mwText.trim()) {
		return `<!doctype html><meta charset="utf-8"><title>empty</title>
			<body style="display:grid;place-items:center;height:100vh;margin:0;font:13px system-ui;color:#94a3b8;background:#0b1221">
				<div>No dated events to show yet.</div>
			</body>`;
	}

	const dir = mkdtempSync(join(tmpdir(), 'rpast-'));
	const input = join(dir, 'in.mw');
	const output = join(dir, `out.${view === 'calendar' ? 'calendar' : 'timeline'}.html`);
	writeFileSync(input, mwText, 'utf-8');

	try {
		const result = spawnSync(process.execPath, [findMwBinary(), input, '-o', view, '-d', output], {
			stdio: ['ignore', 'pipe', 'pipe'],
			timeout: 15_000,
		});
		if (result.status !== 0) {
			const stderr = result.stderr?.toString() ?? '';
			throw new Error(`mw CLI exited ${result.status}: ${stderr.slice(0, 400)}`);
		}
		return readFileSync(output, 'utf-8');
	} finally {
		try { unlinkSync(input); } catch {}
		try { unlinkSync(output); } catch {}
	}
}
