import { NextRequest, NextResponse } from "next/server"; import React from "react"; export const runtime = "nodejs"; export async function POST(req: NextRequest) { try { const data = await req.json(); // Dynamic import to avoid bundling issues const { Document, Page, Text, View, StyleSheet, pdf } = await import("@react-pdf/renderer"); const styles = StyleSheet.create({ page: { padding: 40, fontFamily: "Helvetica", fontSize: 11, color: "#27272a" }, title: { fontSize: 22, fontWeight: "bold", marginBottom: 4 }, subtitle: { fontSize: 11, color: "#71717a" }, divider: { borderBottomWidth: 1, borderBottomColor: "#e4e4e7", marginVertical: 16 }, scoreRow: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, scoreLabel: { fontSize: 10, color: "#a1a1aa" }, scoreValue: { fontSize: 28, fontWeight: "bold" }, clauseCard: { marginBottom: 12, padding: 12, borderWidth: 1, borderColor: "#e4e4e7", borderRadius: 6 }, clauseText: { fontSize: 10, color: "#3f3f46", lineHeight: 1.5, marginBottom: 6 }, tag: { fontSize: 9, fontWeight: "bold", padding: "2 8", borderRadius: 3, marginRight: 4 }, tagHigh: { backgroundColor: "#fef2f2", color: "#b91c1c" }, tagMedium: { backgroundColor: "#fffbeb", color: "#a16207" }, tagLow: { backgroundColor: "#eff6ff", color: "#1d4ed8" }, footer: { position: "absolute", bottom: 30, left: 40, right: 40, fontSize: 8, color: "#a1a1aa", textAlign: "center" }, }); const flagged = (data.results || []).filter((r: any) => r.categories?.length > 0); const doc = React.createElement( Document, null, React.createElement( Page, { size: "A4", style: styles.page }, // Header React.createElement(View, null, React.createElement(Text, { style: styles.title }, "ClauseGuard Report"), React.createElement(Text, { style: styles.subtitle }, `${data.source_url || "Manual scan"} — ${new Date().toLocaleDateString()}` ), ), // Score React.createElement(View, { style: styles.scoreRow }, React.createElement(View, null, React.createElement(Text, { style: styles.scoreLabel }, "RISK SCORE"), React.createElement(Text, { style: styles.scoreValue }, `${data.risk_score}/100`), ), React.createElement(Text, { style: { fontSize: 16, fontWeight: "bold" } }, `Grade ${data.grade}`), ), React.createElement(Text, { style: styles.subtitle }, `${data.total_clauses} clauses scanned — ${data.flagged_count} flagged` ), React.createElement(View, { style: styles.divider }), // Clauses ...flagged.map((clause: any, i: number) => React.createElement(View, { key: i, style: styles.clauseCard }, React.createElement(Text, { style: styles.clauseText }, clause.text?.substring(0, 300) || "" ), React.createElement(View, { style: { flexDirection: "row", flexWrap: "wrap" } }, ...(clause.categories || []).map((cat: any, j: number) => { const tagStyle = cat.severity === "HIGH" ? styles.tagHigh : cat.severity === "MEDIUM" ? styles.tagMedium : styles.tagLow; return React.createElement(Text, { key: j, style: [styles.tag, tagStyle] }, cat.name); }) ), ) ), // Footer React.createElement(Text, { style: styles.footer }, "Generated by ClauseGuard — clauseguard.com — Not legal advice" ), ) ); const instance = pdf(doc); const buffer = await instance.toBuffer(); const chunks: Uint8Array[] = []; for await (const chunk of buffer as any) { chunks.push(chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk)); } return new Response(Buffer.concat(chunks), { headers: { "Content-Type": "application/pdf", "Content-Disposition": `attachment; filename="clauseguard-report.pdf"`, }, }); } catch (error) { console.error("PDF generation error:", error); return NextResponse.json({ error: "PDF generation failed" }, { status: 500 }); } }