/**
 * Saddle-stitch imposition generator using pdf-lib.
 * Reorders PDF pages for 2-up printing on A4/Letter sheets with fold marks.
 */

import { PDFDocument, rgb, LineCapStyle } from "pdf-lib";

const PARENT_SHEETS = {
	A4: { width: 595.28, height: 841.89 },
	"US Letter": { width: 612, height: 792 },
};

const FORMAT_LAYOUT: Record<string, { parent: "A4" | "US Letter"; pagesPerSide: 2 }> = {
	a7: { parent: "A4", pagesPerSide: 2 },
	a6: { parent: "A4", pagesPerSide: 2 },
	"quarter-letter": { parent: "US Letter", pagesPerSide: 2 },
	digest: { parent: "US Letter", pagesPerSide: 2 },
};

/**
 * Generate saddle-stitch signature page order.
 * For N pages (must be multiple of 4):
 *   Sheet 1 front: [N-1, 0], back: [1, N-2]
 *   Sheet 2 front: [N-3, 2], back: [3, N-4]  etc.
 * Returns [leftPage, rightPage] pairs, alternating front/back. 0-indexed.
 */
function saddleStitchOrder(totalPages: number): [number, number][] {
	const pairs: [number, number][] = [];
	const sheets = totalPages / 4;

	for (let i = 0; i < sheets; i++) {
		const frontLeft = totalPages - 1 - 2 * i;
		const frontRight = 2 * i;
		pairs.push([frontLeft, frontRight]);

		const backLeft = 2 * i + 1;
		const backRight = totalPages - 2 - 2 * i;
		pairs.push([backLeft, backRight]);
	}

	return pairs;
}

function drawFoldMarks(
	page: ReturnType<PDFDocument["addPage"]>,
	parentWidth: number,
	parentHeight: number,
) {
	const markLen = 15;
	const markColor = rgb(0.7, 0.7, 0.7);
	const markWidth = 0.5;
	const cx = parentWidth / 2;

	page.drawLine({
		start: { x: cx, y: parentHeight },
		end: { x: cx, y: parentHeight - markLen },
		thickness: markWidth,
		color: markColor,
		lineCap: LineCapStyle.Round,
		dashArray: [3, 3],
	});
	page.drawLine({
		start: { x: cx, y: 0 },
		end: { x: cx, y: markLen },
		thickness: markWidth,
		color: markColor,
		lineCap: LineCapStyle.Round,
		dashArray: [3, 3],
	});
}

export async function generateImposition(
	pdfBuffer: Buffer | Uint8Array,
	formatId: string,
): Promise<{ pdf: Uint8Array; sheetCount: number; pageCount: number }> {
	const layout = FORMAT_LAYOUT[formatId];
	if (!layout) throw new Error(`Imposition not supported for format: ${formatId}`);

	const srcDoc = await PDFDocument.load(pdfBuffer);
	const srcPages = srcDoc.getPages();
	const srcPageCount = srcPages.length;
	const padded = Math.ceil(srcPageCount / 4) * 4;

	const impDoc = await PDFDocument.create();
	const parent = PARENT_SHEETS[layout.parent];
	const pairs = saddleStitchOrder(padded);

	for (const [leftIdx, rightIdx] of pairs) {
		const page = impDoc.addPage([parent.width, parent.height]);
		const bookPageWidth = parent.width / 2;
		const bookPageHeight = parent.height;

		if (leftIdx >= 0 && leftIdx < srcPageCount) {
			const [embedded] = await impDoc.embedPages([srcDoc.getPage(leftIdx)]);
			const srcW = srcPages[leftIdx].getWidth();
			const srcH = srcPages[leftIdx].getHeight();
			const scale = Math.min(bookPageWidth / srcW, bookPageHeight / srcH);
			const scaledW = srcW * scale;
			const scaledH = srcH * scale;
			page.drawPage(embedded, {
				x: (bookPageWidth - scaledW) / 2,
				y: (bookPageHeight - scaledH) / 2,
				width: scaledW,
				height: scaledH,
			});
		}

		if (rightIdx >= 0 && rightIdx < srcPageCount) {
			const [embedded] = await impDoc.embedPages([srcDoc.getPage(rightIdx)]);
			const srcW = srcPages[rightIdx].getWidth();
			const srcH = srcPages[rightIdx].getHeight();
			const scale = Math.min(bookPageWidth / srcW, bookPageHeight / srcH);
			const scaledW = srcW * scale;
			const scaledH = srcH * scale;
			page.drawPage(embedded, {
				x: bookPageWidth + (bookPageWidth - scaledW) / 2,
				y: (bookPageHeight - scaledH) / 2,
				width: scaledW,
				height: scaledH,
			});
		}

		drawFoldMarks(page, parent.width, parent.height);
	}

	const impBytes = await impDoc.save();
	return {
		pdf: impBytes,
		sheetCount: pairs.length / 2,
		pageCount: srcPageCount,
	};
}
