/**
 * Typst compiler — spawns the Typst CLI to generate PDFs.
 *
 * Ported from pocket-press/lib/typst.ts.
 * Uses Bun.spawn() instead of Node execFile().
 */

import { writeFile, readFile, mkdir, unlink } from "node:fs/promises";
import { join, resolve } from "node:path";
import { randomUUID } from "node:crypto";
import type { ParsedDocument } from "./parse-document";

const TYPST_DIR = resolve(import.meta.dir, "typst");

export interface CompileOptions {
	document: ParsedDocument;
	formatId: string;
}

export interface CompileResult {
	pdf: Buffer;
	pageCount: number;
}

export async function compileDocument(options: CompileOptions): Promise<CompileResult> {
	const { document, formatId } = options;
	const jobId = randomUUID();
	const tmpDir = join("/tmp", `rpubs-${jobId}`);
	await mkdir(tmpDir, { recursive: true });

	const dataPath = join(tmpDir, "data.json");
	const driverPath = join(tmpDir, "main.typ");
	const outputPath = join(tmpDir, "output.pdf");

	try {
		// Write the content data as JSON
		await writeFile(dataPath, JSON.stringify(document, null, 2));

		// Write the Typst driver file that imports format + template
		const formatImport = join(TYPST_DIR, "formats", `${formatId}.typ`);
		const templateImport = join(TYPST_DIR, "templates", "pocket-book.typ");

		const driverContent = `
#import "${formatImport}": page-setup
#show: page-setup
#include "${templateImport}"
`;

		await writeFile(driverPath, driverContent);

		// Compile with Typst CLI using Bun.spawn
		const proc = Bun.spawn(
			[
				"typst",
				"compile",
				driverPath,
				outputPath,
				"--root",
				"/",
				"--input",
				`data-path=${dataPath}`,
				"--font-path",
				join(TYPST_DIR, "fonts"),
			],
			{
				stdout: "pipe",
				stderr: "pipe",
			}
		);

		const exitCode = await proc.exited;

		if (exitCode !== 0) {
			const stderr = await new Response(proc.stderr).text();
			throw new Error(`Typst compilation failed: ${stderr}`);
		}

		const pdf = Buffer.from(await readFile(outputPath));

		// Count pages (rough: look for /Type /Page in PDF)
		const pdfStr = pdf.toString("latin1");
		const pageCount = (pdfStr.match(/\/Type\s*\/Page[^s]/g) || []).length;

		return { pdf, pageCount };
	} finally {
		// Clean up temp files
		await Promise.allSettled([
			unlink(dataPath),
			unlink(driverPath),
			unlink(outputPath),
		]).catch(() => {});
		// Remove temp dir (best effort)
		import("node:fs/promises").then(({ rmdir }) => rmdir(tmpDir).catch(() => {}));
	}
}
