import { a as sanitizeXmlColor, n as sanitizeHref } from "./sanitize-O_3j1mNJ.js";

//#region src/renderers/docx.ts
/**
* DOCX renderer — lazy-loads the 'docx' npm package on first use.
*/
function resolveColumn(col) {
	return typeof col === "string" ? { header: col } : col;
}
function getTextContent(children) {
	return children.map((c) => typeof c === "string" ? c : getTextContent(c.children)).join("");
}
/** Parse a data URL and return the base64 data and media type, or null for external URLs. */
function parseDataUrl(src) {
	const match = src.match(/^data:(image\/[^;]+);base64,(.+)$/);
	if (!match) return null;
	return {
		mime: match[1],
		data: match[2]
	};
}
/** Convert page size name to DOCX page dimensions in twips (1 inch = 1440 twips). */
function getPageSize(size, orientation) {
	if (!size) return void 0;
	const dims = {
		A4: {
			width: 11906,
			height: 16838
		},
		A3: {
			width: 16838,
			height: 23811
		},
		A5: {
			width: 8391,
			height: 11906
		},
		letter: {
			width: 12240,
			height: 15840
		},
		legal: {
			width: 12240,
			height: 20160
		},
		tabloid: {
			width: 15840,
			height: 24480
		}
	}[size];
	if (!dims) return void 0;
	if (orientation === "landscape") return {
		width: dims.height,
		height: dims.width
	};
	return dims;
}
/** Convert margin prop to DOCX section margin (in twips, 1pt ~= 20 twips). */
function getPageMargins(margin) {
	if (margin == null) return void 0;
	if (typeof margin === "number") {
		const twips = margin * 20;
		return {
			top: twips,
			right: twips,
			bottom: twips,
			left: twips
		};
	}
	if (margin.length === 2) return {
		top: margin[0] * 20,
		right: margin[1] * 20,
		bottom: margin[0] * 20,
		left: margin[1] * 20
	};
	return {
		top: margin[0] * 20,
		right: margin[1] * 20,
		bottom: margin[2] * 20,
		left: margin[3] * 20
	};
}
/** Map percentage column width to DOCX table column width. */
function getColumnWidth(width) {
	if (width == null) return void 0;
	if (typeof width === "number") return void 0;
	const match = width.match(/^(\d+)%$/);
	if (!match) return void 0;
	return {
		size: Number.parseInt(match[1], 10) * 100,
		type: "pct"
	};
}
function renderHeading(ctx, n) {
	const { docx, children, alignmentMap } = ctx;
	const p = n.props;
	const level = p.level ?? 1;
	const headingMap = {
		1: docx.HeadingLevel.HEADING_1,
		2: docx.HeadingLevel.HEADING_2,
		3: docx.HeadingLevel.HEADING_3,
		4: docx.HeadingLevel.HEADING_4,
		5: docx.HeadingLevel.HEADING_5,
		6: docx.HeadingLevel.HEADING_6
	};
	children.push(new docx.Paragraph({
		heading: headingMap[level] ?? docx.HeadingLevel.HEADING_1,
		children: [new docx.TextRun({
			text: getTextContent(n.children),
			bold: true,
			color: sanitizeXmlColor(p.color)
		})],
		alignment: alignmentMap(p.align)
	}));
}
function renderTextNode(ctx, n) {
	const { docx, children, alignmentMap } = ctx;
	const p = n.props;
	children.push(new docx.Paragraph({
		children: [new docx.TextRun({
			text: getTextContent(n.children),
			...p.bold != null ? { bold: p.bold } : {},
			...p.italic != null ? { italics: p.italic } : {},
			...p.underline ? { underline: {} } : {},
			...p.strikethrough != null ? { strike: p.strikethrough } : {},
			...p.size != null ? { size: p.size * 2 } : {},
			color: sanitizeXmlColor(p.color, "333333")
		})],
		alignment: alignmentMap(p.align),
		spacing: { after: 120 }
	}));
}
function renderLink(ctx, n) {
	const { docx, children } = ctx;
	const p = n.props;
	children.push(new docx.Paragraph({ children: [new docx.ExternalHyperlink({
		link: sanitizeHref(p.href),
		children: [new docx.TextRun({
			text: getTextContent(n.children),
			color: sanitizeXmlColor(p.color, "4f46e5"),
			underline: { type: docx.UnderlineType.SINGLE }
		})]
	})] }));
}
function renderImage(ctx, n) {
	const { docx, children, alignmentMap } = ctx;
	const p = n.props;
	const src = p.src;
	const parsed = parseDataUrl(src);
	if (parsed) {
		const imgWidth = p.width ?? 300;
		const imgHeight = p.height ?? 200;
		children.push(new docx.Paragraph({
			children: [new docx.ImageRun({
				data: Buffer.from(parsed.data, "base64"),
				transformation: {
					width: imgWidth,
					height: imgHeight
				},
				type: parsed.mime === "image/png" ? "png" : "jpg"
			})],
			alignment: alignmentMap(p.align)
		}));
		if (p.caption) children.push(new docx.Paragraph({
			children: [new docx.TextRun({
				text: p.caption,
				italics: true,
				size: 20,
				color: "666666"
			})],
			alignment: alignmentMap(p.align),
			spacing: { after: 120 }
		}));
	} else {
		const alt = p.alt ?? "Image";
		const caption = p.caption ? ` — ${p.caption}` : "";
		children.push(new docx.Paragraph({ children: [new docx.TextRun({
			text: `[${alt}${caption}]`,
			italics: true,
			color: "999999"
		})] }));
	}
}
function renderDocxTable(ctx, n) {
	const { docx, children, alignmentMap } = ctx;
	const p = n.props;
	const columns = (p.columns ?? []).map(resolveColumn);
	const rows = p.rows ?? [];
	const hs = p.headerStyle;
	const borderStyle = p.bordered ? {
		style: docx.BorderStyle.SINGLE,
		size: 1,
		color: "DDDDDD"
	} : void 0;
	const cellBorders = borderStyle ? {
		top: borderStyle,
		bottom: borderStyle,
		left: borderStyle,
		right: borderStyle
	} : void 0;
	const headerRow = new docx.TableRow({
		tableHeader: true,
		children: columns.map((col) => new docx.TableCell({
			children: [new docx.Paragraph({
				children: [new docx.TextRun({
					text: col.header,
					bold: true,
					color: sanitizeXmlColor(hs?.color)
				})],
				alignment: alignmentMap(col.align)
			})],
			...hs?.background ? { shading: {
				fill: sanitizeXmlColor(hs.background),
				type: docx.ShadingType.SOLID
			} } : {},
			...cellBorders != null ? { borders: cellBorders } : {},
			width: getColumnWidth(col.width)
		}))
	});
	const dataRows = rows.map((row, rowIdx) => new docx.TableRow({ children: columns.map((col, colIdx) => new docx.TableCell({
		children: [new docx.Paragraph({
			children: [new docx.TextRun({ text: String(row[colIdx] ?? "") })],
			alignment: alignmentMap(col.align)
		})],
		...p.striped && rowIdx % 2 === 1 ? { shading: {
			fill: "F9F9F9",
			type: docx.ShadingType.SOLID
		} } : {},
		...cellBorders != null ? { borders: cellBorders } : {},
		width: getColumnWidth(col.width)
	})) }));
	if (p.caption) children.push(new docx.Paragraph({
		children: [new docx.TextRun({
			text: p.caption,
			italics: true,
			size: 20
		})],
		spacing: { after: 60 }
	}));
	children.push(new docx.Table({
		rows: [headerRow, ...dataRows],
		width: {
			size: 100,
			type: docx.WidthType.PERCENTAGE
		}
	}));
	children.push(new docx.Paragraph({
		text: "",
		spacing: { after: 120 }
	}));
}
function renderList(ctx, n) {
	const { docx, children, processListItems, nextListId } = ctx;
	const ordered = n.props.ordered;
	processListItems(n, nextListId(), 0, ordered ?? false);
	children.push(new docx.Paragraph({
		text: "",
		spacing: { after: 60 }
	}));
}
function renderButtonOrQuote(ctx, n) {
	const { docx, children } = ctx;
	const p = n.props;
	const text = getTextContent(n.children);
	if (n.type === "button") children.push(new docx.Paragraph({
		children: [new docx.ExternalHyperlink({
			link: sanitizeHref(p.href),
			children: [new docx.TextRun({
				text,
				bold: true,
				color: "4F46E5",
				underline: { type: docx.UnderlineType.SINGLE }
			})]
		})],
		spacing: { after: 120 }
	}));
	else children.push(new docx.Paragraph({
		children: [new docx.TextRun({
			text,
			italics: true,
			color: "555555"
		})],
		indent: { left: 720 },
		border: { left: {
			style: docx.BorderStyle.SINGLE,
			size: 6,
			color: sanitizeXmlColor(p.borderColor, "DDDDDD")
		} },
		spacing: { after: 120 }
	}));
}
const docxRenderer = { async render(node, _options) {
	let docx;
	try {
		docx = await import("./dist-CYL41kqQ.js");
	} catch {
		throw new Error("[@pyreon/document] DOCX renderer requires \"docx\" package. Install it: bun add docx");
	}
	const children = [];
	let listCounter = 0;
	function alignmentMap(align) {
		if (!align) return void 0;
		return {
			left: docx.AlignmentType.LEFT,
			center: docx.AlignmentType.CENTER,
			right: docx.AlignmentType.RIGHT,
			justify: docx.AlignmentType.JUSTIFIED
		}[align];
	}
	function processListItems(n, listRef, level, ordered) {
		const items = n.children.filter((c) => typeof c !== "string");
		for (const item of items) {
			const nestedList = item.children.find((c) => typeof c !== "string" && c.type === "list");
			const textChildren = item.children.filter((c) => typeof c === "string" || c.type !== "list");
			children.push(new docx.Paragraph({
				children: [new docx.TextRun({ text: getTextContent(textChildren) })],
				...ordered ? { numbering: {
					reference: listRef,
					level
				} } : { bullet: { level } }
			}));
			if (nestedList) {
				const nestedOrdered = nestedList.props.ordered;
				processListItems(nestedList, listRef, level + 1, nestedOrdered ?? false);
			}
		}
	}
	const ctx = {
		docx,
		children,
		alignmentMap,
		processListItems,
		nextListId: () => `list-${listCounter++}`
	};
	function processNode(n) {
		switch (n.type) {
			case "document":
			case "page":
			case "section":
			case "row":
			case "column":
				for (const child of n.children) if (typeof child !== "string") processNode(child);
				else children.push(new docx.Paragraph({ text: child }));
				break;
			case "heading":
				renderHeading(ctx, n);
				break;
			case "text":
				renderTextNode(ctx, n);
				break;
			case "link":
				renderLink(ctx, n);
				break;
			case "image":
				renderImage(ctx, n);
				break;
			case "table":
				renderDocxTable(ctx, n);
				break;
			case "list":
				renderList(ctx, n);
				break;
			case "code":
				children.push(new docx.Paragraph({
					children: [new docx.TextRun({
						text: getTextContent(n.children),
						font: "Courier New",
						size: 20
					})],
					shading: {
						fill: "F5F5F5",
						type: docx.ShadingType.SOLID
					},
					spacing: { after: 120 }
				}));
				break;
			case "divider":
				children.push(new docx.Paragraph({
					border: { bottom: {
						style: docx.BorderStyle.SINGLE,
						size: n.props.thickness ?? 1,
						color: sanitizeXmlColor(n.props.color, "DDDDDD")
					} },
					spacing: {
						before: 120,
						after: 120
					}
				}));
				break;
			case "spacer":
				children.push(new docx.Paragraph({
					text: "",
					spacing: { after: n.props.height * 20 }
				}));
				break;
			case "button":
			case "quote":
				renderButtonOrQuote(ctx, n);
				break;
		}
	}
	processNode(node);
	const numberingConfigs = [];
	for (let i = 0; i < listCounter; i++) numberingConfigs.push({
		reference: `list-${i}`,
		levels: Array.from({ length: 9 }, (_, level) => ({
			level,
			format: docx.LevelFormat.DECIMAL,
			text: `%${level + 1}.`,
			alignment: docx.AlignmentType.LEFT,
			style: { paragraph: { indent: {
				left: 720 * (level + 1),
				hanging: 360
			} } }
		}))
	});
	const pageProps = (node.type === "document" ? node.children.find((c) => typeof c !== "string" && c.type === "page") : node.type === "page" ? node : void 0)?.props ?? {};
	const pageDims = getPageSize(pageProps.size, pageProps.orientation);
	const pageMargins = getPageMargins(pageProps.margin);
	function buildHeaderFooter(contentNode) {
		if (!contentNode) return void 0;
		const text = getTextContent(contentNode.children);
		if (!text) return void 0;
		return [new docx.Paragraph({
			children: [new docx.TextRun({
				text,
				size: 18,
				color: "999999"
			})],
			alignment: docx.AlignmentType.CENTER
		})];
	}
	const headerContent = buildHeaderFooter(pageProps.header);
	const footerContent = buildHeaderFooter(pageProps.footer);
	const sectionProperties = {};
	if (pageDims) sectionProperties.page = {
		size: pageDims,
		margin: pageMargins
	};
	else if (pageMargins) sectionProperties.page = { margin: pageMargins };
	const doc = new docx.Document({
		numbering: numberingConfigs.length > 0 ? { config: numberingConfigs } : void 0,
		sections: [{
			properties: sectionProperties,
			...headerContent ? { headers: { default: new docx.Header({ children: headerContent }) } } : {},
			...footerContent ? { footers: { default: new docx.Footer({ children: footerContent }) } } : {},
			children
		}]
	});
	const buffer = await docx.Packer.toBuffer(doc);
	return new Uint8Array(buffer);
} };

//#endregion
export { docxRenderer };
//# sourceMappingURL=docx-uNAel545.js.map