import { PDFDocument, PDFImage, StandardFonts, rgb } from '@cantoo/pdf-lib';
import { readFile, writeFile, rename } from 'node:fs/promises';
import type { SignatureFieldData } from '@/lib/db/schema';
import { getFieldType } from '@/lib/db/schema';

/**
 * Draws signature/field placeholders and text values on a PDF.
 * Uses atomic write: write to tmp path, verify %PDF header, rename to final path.
 *
 * Text fill: textFields is keyed by SignatureFieldData.id (UUID). Each text-type
 * placed field box has its value looked up directly by field ID and drawn at
 * the field's coordinates.
 *
 * @param srcPath     - Absolute path to original PDF
 * @param destPath    - Absolute path to write prepared PDF (e.g. {docId}_prepared.pdf)
 * @param textFields  - Key/value map: { [fieldId (UUID)]: value } (agent-provided)
 * @param sigFields   - Signature field array from SignatureFieldData[]
 */
export async function preparePdf(
  srcPath: string,
  destPath: string,
  textFields: Record<string, string>,
  sigFields: SignatureFieldData[],
  agentSignatureData: string | null = null,
  agentInitialsData: string | null = null,
): Promise<void> {
  const pdfBytes = await readFile(srcPath);
  const pdfDoc = await PDFDocument.load(pdfBytes);
  const helvetica = await pdfDoc.embedFont(StandardFonts.Helvetica);
  const pages = pdfDoc.getPages();

  // Embed agent signature image once — reused across all agent-sig fields
  let agentSigImage: PDFImage | null = null;
  if (agentSignatureData) {
    agentSigImage = await pdfDoc.embedPng(agentSignatureData);
  }

  // Embed agent initials image once — reused across all agent-initials fields
  let agentInitialsImage: PDFImage | null = null;
  if (agentInitialsData) {
    agentInitialsImage = await pdfDoc.embedPng(agentInitialsData);
  }

  // Phase 12.1: Draw text values at placed text field boxes — keyed by field ID (UUID)
  for (const field of sigFields) {
    if (getFieldType(field) !== 'text') continue;
    const value = textFields[field.id];
    if (!value) continue;
    const page = pages[field.page - 1];
    if (!page) continue;
    const fontSize = Math.max(6, Math.min(11, field.height - 4));
    page.drawText(value, {
      x: field.x + 4,
      y: field.y + 4,
      size: fontSize,
      font: helvetica,
      color: rgb(0.05, 0.05, 0.05),
    });
  }

  // Draw field placeholders — rendering varies by field type
  for (const field of sigFields) {
    const page = pages[field.page - 1]; // page is 1-indexed
    if (!page) continue;
    const fieldType = getFieldType(field);

    if (fieldType === 'client-signature') {
      // Blue "Sign Here" placeholder — transparent background, border + label only
      page.drawRectangle({
        x: field.x, y: field.y, width: field.width, height: field.height,
        borderColor: rgb(0.15, 0.39, 0.92), borderWidth: 1.5,
      });
      page.drawText('Sign Here', {
        x: field.x + 4, y: field.y + 4, size: 8, font: helvetica,
        color: rgb(0.15, 0.39, 0.92),
      });

    } else if (fieldType === 'initials') {
      // Purple "Initials" placeholder — transparent background, border + label only
      page.drawRectangle({
        x: field.x, y: field.y, width: field.width, height: field.height,
        borderColor: rgb(0.49, 0.23, 0.93), borderWidth: 1.5,
      });
      page.drawText('Initials', {
        x: field.x + 4, y: field.y + 4, size: 8, font: helvetica,
        color: rgb(0.49, 0.23, 0.93),
      });

    } else if (fieldType === 'checkbox') {
      // X mark only — no background or border so underlying PDF content shows through
      page.drawLine({
        start: { x: field.x + 2, y: field.y + 2 },
        end: { x: field.x + field.width - 2, y: field.y + field.height - 2 },
        thickness: 1.5, color: rgb(0.1, 0.1, 0.1),
      });
      page.drawLine({
        start: { x: field.x + field.width - 2, y: field.y + 2 },
        end: { x: field.x + 2, y: field.y + field.height - 2 },
        thickness: 1.5, color: rgb(0.1, 0.1, 0.1),
      });

    } else if (fieldType === 'date') {
      // No placeholder drawn — actual signing date stamped at POST time in route.ts

    } else if (fieldType === 'text') {
      // Text value drawn in field-ID loop above (Phase 12.1).
      // No additional marker drawn here.

    } else if (fieldType === 'agent-signature') {
      if (agentSigImage) {
        page.drawImage(agentSigImage, {
          x: field.x,
          y: field.y,
          width: field.width,
          height: field.height,
        });
      }
      // If no signature saved: the prepare route guards against this with 422 before calling preparePdf

    } else if (fieldType === 'agent-initials') {
      if (agentInitialsImage) {
        page.drawImage(agentInitialsImage, {
          x: field.x,
          y: field.y,
          width: field.width,
          height: field.height,
        });
      }
      // If no initials saved: the prepare route guards against this with 422 before calling preparePdf
    }
  }

  const modifiedBytes = await pdfDoc.save();

  // Atomic write: tmp → rename (prevents partial writes from corrupting the only copy)
  const tmpPath = `${destPath}.tmp`;
  await writeFile(tmpPath, modifiedBytes);

  // Verify output is a valid PDF (check magic bytes)
  const magic = modifiedBytes.slice(0, 4);
  const header = Buffer.from(magic).toString('ascii');
  if (!header.startsWith('%PDF')) {
    throw new Error('preparePdf: output is not a valid PDF (magic bytes check failed)');
  }

  await rename(tmpPath, destPath);
}
