import { NextResponse } from 'next/server';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { parseBody } from '@/lib/api/route-helpers';
import { errorResponse, ValidationError } from '@/lib/errors';
import { generatePdf } from '@/lib/pdf/generate';
import {
  validateTipTapDocument,
  tipTapToPdfmeTemplate,
  buildContentInputsFromDoc,
  substituteVariables,
  type TipTapNode,
} from '@/lib/pdf/tiptap-to-pdfme';
import { previewAdminTemplateSchema } from '@/lib/validators/document-templates';

/**
 * POST /api/v1/admin/templates/preview
 *
 * Generates a preview PDF from a TipTap JSON content block.
 * Returns { data: { pdfBase64: string } } — the client can render this
 * in an <iframe src="data:application/pdf;base64,..."> or open in a new tab.
 *
 * Body:
 *   content: TipTap JSON document
 *   sampleData?: Record<string, string> — variable substitutions
 */
export const POST = withAuth(
  withPermission('documents', 'manage', async (req, _ctx) => {
    try {
      const body = await parseBody(req, previewAdminTemplateSchema);

      const doc = body.content as unknown as TipTapNode;
      const sampleData = body.sampleData ?? {};

      // Validate content nodes
      const unsupported = validateTipTapDocument(doc);
      if (unsupported.length > 0) {
        throw new ValidationError(
          `Content contains unsupported node types: ${unsupported.join(', ')}`,
        );
      }

      // Substitute variables in text nodes
      const substitutedDoc = substituteInDoc(doc, sampleData);

      // Convert to pdfme template + inputs
      const template = tipTapToPdfmeTemplate(substitutedDoc);
      const inputs = buildContentInputsFromDoc(substitutedDoc, template);

      const pdfBytes = await generatePdf(template, inputs);
      const pdfBase64 = Buffer.from(pdfBytes).toString('base64');

      return NextResponse.json({ data: { pdfBase64 } });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);

/**
 * Deeply substitutes {{variable}} tokens in all text nodes of a TipTap doc.
 */
function substituteInDoc(
  node: TipTapNode,
  data: Record<string, string>,
): TipTapNode {
  if (node.type === 'text' && node.text) {
    return { ...node, text: substituteVariables(node.text, data) };
  }
  if (node.content) {
    return {
      ...node,
      content: node.content.map((child) => substituteInDoc(child, data)),
    };
  }
  return node;
}
