// src/certificates/certificate-draft-generator.service.ts
import { Injectable } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';
import * as https from 'https';
import * as http from 'http';
import * as puppeteer from 'puppeteer';
import {
  Document,
  Packer,
  Paragraph,
  TextRun,
  AlignmentType,
  ImageRun,
  WidthType,
  Table,
  TableRow,
  TableCell,
  BorderStyle,
  VerticalAlign,
  LevelFormat,
} from 'docx';

// Generic interface — works with your Certificate entity
export interface CertificateForDraft {
  id: number;
  cert_no?: string;
  certificate_no?: string;
  certificate_number?: string;
  scope_of_work?: string;
  ea_codes?: string;
  originally_registered?: string | Date | null;
  issue_date?: string | Date | null;
  expire_date?: string | Date | null;
  expiry_date?: string | Date | null;
  // ✅ NEW — surveillance + recertification dates
  surveillance_audit_due?: string | Date | null;
  recertification_due?: string | Date | null;
  qrCode?: string | null;
  qr_code?: string | null;
  qr_code_data?: string | null;
  verification_url?: string | null;
  city?: string;
  country?: string;
  company?: {
    name?: string;
    address?: string;
    accreditation?: string;
    city?: string;
    country?: any;
  };
  standard?: {
    id?: number;
    name?: string;
    title?: string;
  };
}

@Injectable()
export class CertificateDraftGeneratorService {
  // ── Format date to "15 MAY 2026" ─────────────────────────────
  private formatDate(dateInput: string | Date | null | undefined): string {
    if (!dateInput) return 'N/A';
    const months = [
      'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN',
      'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC',
    ];
    const d = new Date(dateInput);
    if (isNaN(d.getTime())) return String(dateInput);
    return `${d.getDate()} ${months[d.getMonth()]} ${d.getFullYear()}`;
  }

  private getCertNo(cert: CertificateForDraft): string {
    return cert.certificate_no || cert.cert_no || cert.certificate_number || 'N/A';
  }

  private getQrCodeData(cert: CertificateForDraft): string | null {
    return cert.qrCode || cert.qr_code || cert.qr_code_data || null;
  }

  private getExpireDate(cert: CertificateForDraft): string | Date | null | undefined {
    return cert.expire_date || cert.expiry_date;
  }

  private base64ToBuffer(base64String: string): Buffer | null {
    if (!base64String) return null;
    try {
      const base64Data = base64String.replace(/^data:image\/\w+;base64,/, '');
      return Buffer.from(base64Data, 'base64');
    } catch (err) {
      console.error('Failed to convert QR base64 to buffer:', err);
      return null;
    }
  }

  // ✅ NEW — small helper to safely uppercase any string-ish value
  private uc(value: string | null | undefined): string {
    if (!value) return '';
    return String(value).toUpperCase();
  }

  // ✅ FIXED — much smarter scope splitting (handles all common delimiters)
  // Splits on: newlines, commas, semicolons, "&", "•", "▪", arrows, em-dashes, multiple spaces, bullets
  // Trims, deduplicates, drops fragments < 3 chars (which are usually noise)
  private getScopeItems(scopeOfWork?: string): string[] {
    if (!scopeOfWork) return [];

    // Strip any existing bullets/arrows that may already be in the source text
    const cleaned = scopeOfWork
      .replace(/[➤➢►▶◆●◦◯○▪■□☐»]/g, '\n')        // common bullets → newline
      .replace(/[\u2022\u25BA\u25B6\u25CF\u00BB]/g, '\n') // unicode bullets → newline
      .replace(/[—–]/g, '\n');                     // em/en dash → newline

    // Split on the major delimiters
    const parts = cleaned
      .split(/\r?\n|;|&|\|/)                         // newlines, semicolons, &, pipes
      .flatMap((s) => s.split(/,(?![^()]*\))/))      // commas (but not inside parens)
      .map((s) => s.trim())
      .filter((s) => s.length >= 3);                 // drop empty / 1–2 char garbage

    // Dedupe while preserving order
    const seen = new Set<string>();
    const out: string[] = [];
    for (const item of parts) {
      const key = item.toUpperCase();
      if (!seen.has(key)) {
        seen.add(key);
        out.push(item);
      }
    }
    return out;
  }

  private ensureFolder(): string {
    const folder = path.join(process.cwd(), 'uploads', 'certificates');
    if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
    return folder;
  }

  private async loadSignature(): Promise<Buffer | null> {
    const localPaths = [
      path.join(process.cwd(), 'src', 'static', 'sign-remove.png'),
      path.join(process.cwd(), 'static', 'sign-remove.png'),
      path.join(process.cwd(), 'public', 'static', 'sign-remove.png'),
      path.join(process.cwd(), 'assets', 'sign-remove.png'),
      path.join(process.cwd(), 'src', 'assets', 'sign-remove.png'),
    ];

    for (const p of localPaths) {
      if (fs.existsSync(p)) {
        console.log('✅ Signature loaded from local path:', p);
        return fs.readFileSync(p);
      }
    }

    try {
      const buf = await this.downloadBuffer(
        'http://localhost:3000/static/sign-remove.png',
      );
      if (buf && buf.length > 100) {
        console.log('✅ Signature loaded via localhost HTTP');
        return buf;
      }
    } catch {
      /* continue */
    }

    try {
      const buf = await this.downloadBuffer(
        'https://scheme.qrs.ae/static/sign-remove.png',
      );
      if (buf && buf.length > 100) {
        console.log('✅ Signature loaded via HTTPS URL');
        return buf;
      }
    } catch {
      /* continue */
    }

    console.warn('⚠️ Signature image not found — proceeding without it');
    return null;
  }

  private downloadBuffer(url: string): Promise<Buffer> {
    return new Promise((resolve, reject) => {
      const client = url.startsWith('https') ? https : http;
      const req = client.get(url, { timeout: 5000 }, (res) => {
        if (res.statusCode !== 200) {
          reject(new Error(`HTTP ${res.statusCode}`));
          return;
        }
        const chunks: Buffer[] = [];
        res.on('data', (c) => chunks.push(c));
        res.on('end', () => resolve(Buffer.concat(chunks)));
        res.on('error', reject);
      });
      req.on('error', reject);
      req.on('timeout', () => {
        req.destroy();
        reject(new Error('timeout'));
      });
    });
  }

  private noBorder() {
    return {
      top: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
      bottom: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
      left: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
      right: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
    };
  }

  // ═══════════════════════════════════════════════════════════════
  // PDF — A4 size, optional DRAFT watermark, with QR code below sig
  // ═══════════════════════════════════════════════════════════════
  private buildPageHtml(
    cert: CertificateForDraft,
    isDraft: boolean = false,
  ): string {
    const scopeItems = this.getScopeItems(cert.scope_of_work);
    // ✅ CHANGED — arrow is now » double chevron (U+00BB) to match draft
    const scopeHtml = scopeItems
      .map(
        (item) => `
        <li style="
          margin: 4px 0;
          padding: 0;
          line-height: 1.5;
          display: flex;
          align-items: flex-start;
        ">
          <span style="
            display: inline-block;
            width: 18px;
            color: #000;
            font-weight: bold;
            flex-shrink: 0;
          ">&#10146;</span>
          <span style="flex: 1;">${item}</span>
        </li>`,
      )
      .join('');

    const qrCodeData = this.getQrCodeData(cert);
    const certNo = this.getCertNo(cert);
    const standard = cert.standard ?? { name: '', title: '' };
    const expireDate = this.getExpireDate(cert);

    // ✅ NEW — pre-format the two new date fields
    const survAuditDate = cert.surveillance_audit_due
      ? this.formatDate(cert.surveillance_audit_due)
      : null;
    const recertDate = cert.recertification_due
      ? this.formatDate(cert.recertification_due)
      : null;

    // ✅ NEW — UPPERCASE company name, address, country
    const companyNameUpper = this.uc(cert.company?.name);
    const addressUpper = this.uc(cert.company?.address ?? cert.city);
    const countryUpper = this.uc(cert.country);

    // ✅ QR HTML — will go BELOW signature (under "Quality Registrar Systems")
    const qrHtml = qrCodeData
      ? `<div style="margin-top:8px; text-align:center;">
           <img
             src="${qrCodeData}"
             style="width:90px; height:90px; display:block; margin:0 auto; image-rendering:pixelated;"
             alt="QR Code"
           />
           <p style="font-size:9px; margin:2px 0 0; color:#666;">Scan to verify</p>
         </div>`
      : '';

    const watermarkHtml = isDraft
      ? `<div style="
          position:fixed; top:50%; left:50%;
          transform:translate(-50%,-50%) rotate(-30deg);
          font-size:140px; font-weight:900; letter-spacing:10px;
          color:rgba(180,180,180,0.18); pointer-events:none;
          white-space:nowrap; z-index:0;
        ">DRAFT</div>`
      : '';

    return `
      <div style="
        width:210mm; min-height:297mm; position:relative;
        font-family:'Calibri',sans-serif; background:#fff;
        page-break-after:always; overflow:hidden;
      ">
        ${watermarkHtml}

        <!-- Content -->
        <div style="
          position:relative; z-index:1;
          padding:40px 45px 40px; text-align:center;
        ">
          <!-- ✅ Company name — UPPERCASE, regular weight, MORE space from top -->
          <h2 style="
            font-size:27px; font-weight:400;
            margin:80px auto 6px; max-width:90%; line-height:1.1em;
          ">${companyNameUpper}</h2>

          <p style="font-size:13px; margin:4px 0 2px;">at</p>

          <!-- ✅ Address + Country — UPPERCASE -->
          <p style="
            font-size:13px; margin:2px auto 10px; max-width:90%;
            word-break:break-word; line-height:1.35;
          ">${addressUpper}${countryUpper ? ', ' + countryUpper : ''}</p>

          <p style="
            font-size:0.9em; line-height:1.35; text-align:center;
            margin:2px auto 10px; max-width:90%;
          ">
            Quality Registrar Systems certify that the management system of the
            above organization has been audited and found to be in compliance with
            the QRS &amp; ISO standard requirements for registration of the
            management system standard detailed below:
          </p>

          <!-- ✅ Standard — BOLD -->
          <h3 style="
            font-size:1.8em; font-weight:700;
            margin:0; line-height:1.1em;
          ">${standard.name ?? ''}</h3>
          <p style="font-size:0.9em; margin:0; padding-top:2px; line-height:1.1em;">
            ${standard.title ?? ''}
          </p>

          <!-- ✅ Scope — each item on its own line, » double chevron -->
          <div style="width:90%; margin:14px auto 22px; text-align:left;">
            <p style="
              font-weight:normal;
              text-align:center;
              margin-bottom:8px;
              font-size:0.95em;
            ">Scope of work</p>
            <ul style="
              list-style:none;
              padding-left:1.4em;
              margin:0;
              font-size:0.85em;
              line-height:1.5;
            ">
              ${scopeHtml}
            </ul>
          </div>

          <!-- 3 columns — Dates Left | New Dates Middle | Signature+QR Right -->
          <div style="
            display:grid;
            grid-template-columns:1.2fr 1.2fr 1fr;
            gap: 12px;
            width:95%;
            margin:0 auto;
            text-align:left;
          ">
            <!-- LEFT COLUMN: Original dates -->
            <div>
              <p style="margin:2px 0; font-size:0.85em;">
                EA &nbsp;&nbsp;${cert.ea_codes ?? cert.company?.accreditation ?? ''}
              </p>
              <p style="margin:2px 0; font-size:0.85em;">
                Certificate No: ${certNo}
              </p>
              <p style="margin:2px 0; font-size:0.85em;">
                Originally Registered: ${this.formatDate(cert.originally_registered)}
              </p>
              <p style="margin:2px 0; font-size:0.85em;">
                Latest Issue: ${this.formatDate(cert.issue_date)}
              </p>
              <p style="margin:2px 0; font-size:0.85em;">
                Valid up-to: ${this.formatDate(expireDate)}
              </p>
            </div>

            <!-- MIDDLE COLUMN: Surv + Recert dates -->
            <div>
              ${
                survAuditDate
                  ? `<p style="margin:2px 0; font-size:0.85em;">
                       SURV. AUDIT ON OR BEFORE: ${survAuditDate}
                     </p>`
                  : ''
              }
              ${
                recertDate
                  ? `<p style="margin:2px 0; font-size:0.85em;">
                       RE-CERTIFICATION DUE ON: ${recertDate}
                     </p>`
                  : ''
              }
            </div>

            <!-- RIGHT COLUMN: Signature + QR (stacked vertically) -->
            <div style="text-align:center; margin-top:-20px;">
              <img
                src="https://scheme.qrs.ae/static/sign-remove.png"
                style="width:160px; display:block; margin:0 auto;"
                alt="Signature"
              />
              <div style="
                width:174px; height:1px; background:#000;
                margin:1px auto 5px;
              "></div>
              <p style="font-size:0.85em; font-weight:600; margin-top:3px;">
                Quality Registrar Systems
              </p>

              <!-- QR Code BELOW Quality Registrar Systems text -->
              ${qrHtml}
            </div>
          </div>

        </div>
      </div>
    `;
  }

  async generatePdf(
    cert: CertificateForDraft,
    options: { draft?: boolean } = {},
  ): Promise<string> {
    if (!cert.standard) {
      throw new Error('Certificate has no standard linked');
    }

    const isDraft = !!options.draft;
    const pageHtml = this.buildPageHtml(cert, isDraft);

    const fullHtml = `
      <!DOCTYPE html><html>
      <head>
        <meta charset="UTF-8">
        <style>
          * { box-sizing:border-box; margin:0; padding:0; }
          @page { size:A4; margin:0; }
          body { margin:0; padding:0; background:#fff; }
        </style>
      </head>
      <body>${pageHtml}</body>
      </html>
    `;

    const browser = await puppeteer.launch({
      headless: true,
      args: ['--no-sandbox', '--disable-setuid-sandbox'],
    });

    try {
      const page = await browser.newPage();
      await page.setContent(fullHtml, { waitUntil: 'domcontentloaded' });
      await page.evaluateHandle('document.fonts.ready');

      await page.evaluate(async () => {
        const images = Array.from(document.images);
        await Promise.all(
          images.map((img) => {
            if (img.complete) return;
            return new Promise<void>((resolve) => {
              img.onload = () => resolve();
              img.onerror = () => resolve();
            });
          }),
        );
      });

      const pdfBuffer = await page.pdf({
        format: 'A4',
        printBackground: true,
        margin: { top: '0mm', right: '0mm', bottom: '0mm', left: '0mm' },
      });

      const folder = this.ensureFolder();
      const certNo = this.getCertNo(cert).replace(/[^a-zA-Z0-9-]/g, '_');
      const suffix = isDraft ? '_DRAFT' : '';
      const fileName = `${certNo}${suffix}.pdf`;
      const filePath = path.join(folder, fileName);

      fs.writeFileSync(filePath, Buffer.from(pdfBuffer));
      return `uploads/certificates/${fileName}`;
    } finally {
      await browser.close();
    }
  }

  // ═══════════════════════════════════════════════════════════════
  // WORD — A4, NO watermark, QR below signature (same column)
  //   ✅ Calibri body, » double-chevron bullets via native list
  //   ✅ UPPERCASE company name, address, country
  //   ✅ Fully editable — no content controls, no locked sections
  // ═══════════════════════════════════════════════════════════════
  async generateDocx(cert: CertificateForDraft): Promise<string> {
    if (!cert.standard) {
      throw new Error('Certificate has no standard linked');
    }

    const standard = cert.standard;
    const certNo = this.getCertNo(cert);
    const expireDate = this.getExpireDate(cert);
    const scopeItems = this.getScopeItems(cert.scope_of_work);

    // ✅ NEW — pre-format the two new date fields
    const survAuditDate = cert.surveillance_audit_due
      ? this.formatDate(cert.surveillance_audit_due)
      : null;
    const recertDate = cert.recertification_due
      ? this.formatDate(cert.recertification_due)
      : null;

    // ✅ NEW — UPPERCASE company name, address, country
    const companyNameUpper = this.uc(cert.company?.name);
    const addressUpper = this.uc(cert.company?.address ?? cert.city);
    const countryUpper = this.uc(cert.country);
    const fullAddressUpper =
      addressUpper + (countryUpper ? ', ' + countryUpper : '');

    const signatureBuffer = await this.loadSignature();

    const qrCodeData = this.getQrCodeData(cert);
    const qrBuffer = qrCodeData ? this.base64ToBuffer(qrCodeData) : null;

    // ✅ Native bullet numbering — using » double chevron
    // This makes each scope item a real list item, so the user can hit Enter
    // in Word and get a new bullet automatically (fully editable).
    const numberingConfig = {
      config: [
        {
          reference: 'scopeBullets',
          levels: [
            {
              level: 0,
              format: LevelFormat.BULLET,
              text: '\u27A2', // ➢ standard Word arrow bullet (matches draft)
              alignment: AlignmentType.LEFT,
              style: {
                paragraph: { indent: { left: 720, hanging: 360 } },
                run: { font: 'Calibri', size: 20 },
              },
            },
          ],
        },
      ],
    };

    const sections = [
      {
        // ✅ No SectionType.CONTINUOUS — keeps the doc as a single clean section
        properties: {
          page: {
            size: { width: 11906, height: 16838 }, // A4
            margin: { top: 720, bottom: 720, left: 900, right: 900 },
          },
        },

        children: [
          // ✅ Top spacer — extra space from top
          new Paragraph({ spacing: { before: 600, after: 0 } }),

          // ── Company Name — UPPERCASE, regular weight (Calibri Body)
          new Paragraph({
            alignment: AlignmentType.CENTER,
            spacing: { before: 280, after: 80 },
            children: [
              new TextRun({
                text: companyNameUpper,
                size: 54,
                bold: false,
              }),
            ],
          }),

          // ── "at" ──────────────────────────────────────────────
          new Paragraph({
            alignment: AlignmentType.CENTER,
            spacing: { before: 40, after: 40 },
            children: [new TextRun({ text: 'at', size: 24 })],
          }),

          // ── ✅ Address + Country — UPPERCASE ──────────────────
          new Paragraph({
            alignment: AlignmentType.CENTER,
            spacing: { before: 40, after: 100 },
            children: [
              new TextRun({
                text: fullAddressUpper,
                size: 22,
              }),
            ],
          }),

          // ── Compliance Text ───────────────────────────────────
          new Paragraph({
            alignment: AlignmentType.CENTER,
            spacing: { before: 80, after: 80 },
            children: [
              new TextRun({
                text:
                  'Quality Registrar Systems certify that the management system of the above ' +
                  'organization has been audited and found to be in compliance with the QRS & ISO ' +
                  'standard requirements for registration of the management system standard detailed below:',
                size: 22,
              }),
            ],
          }),

          // ── Standard Name — regular weight (Calibri Body)
          new Paragraph({
            alignment: AlignmentType.CENTER,
            spacing: { before: 60, after: 40 },
            children: [
              new TextRun({
                text: standard.name ?? '',
                size: 56,
                bold: false,
              }),
            ],
          }),

          // ── Standard Title ────────────────────────────────────
          new Paragraph({
            alignment: AlignmentType.CENTER,
            spacing: { before: 40, after: 100 },
            children: [
              new TextRun({
                text: standard.title ?? '',
                size: 24,
              }),
            ],
          }),

          // ── Scope of Work Title ───────────────────────────────
          new Paragraph({
            alignment: AlignmentType.CENTER,
            spacing: { before: 60, after: 80 },
            children: [
              new TextRun({ text: 'Scope of work', size: 24 }),
            ],
          }),

          // ── ✅ Scope Items — native bullet list with ➢ arrow
          //    Tight spacing to match draft. Fully editable: pressing
          //    Enter in Word adds a new bullet automatically.
          ...scopeItems.map(
            (item) =>
              new Paragraph({
                numbering: { reference: 'scopeBullets', level: 0 },
                spacing: { before: 0, after: 0, line: 260 },
                children: [
                  new TextRun({
                    text: item,
                    size: 20,
                  }),
                ],
              }),
          ),

          // ── Spacer ────────────────────────────────────────────
          new Paragraph({ spacing: { before: 200, after: 0 } }),

          // ── 2-column, 2-row TABLE matching the draft exactly:
          //
          //   ┌────────────────────────┬────────────────────────────────┐
          //   │ EA 17                  │                                │
          //   │ Certificate No: ...    │                                │
          //   │ Originally Reg: ...    │                                │
          //   │ Latest Issue: ...      │ SURV. AUDIT ON OR BEFORE: ...  │  ← bottom-aligned
          //   │ Valid up-to: ...       │ RE-CERTIFICATION DUE ON: ...   │
          //   ├────────────────────────┼────────────────────────────────┤
          //   │                        │       [signature image]        │
          //   │                        │       _______________          │
          //   │                        │   Quality Registrar Systems    │
          //   │                        │       [QR code if any]         │
          //   └────────────────────────┴────────────────────────────────┘
          //
          // Fully editable in Word — user can click any cell, edit text,
          // add new lines, drag the table, etc.
          new Table({
            width: { size: 9200, type: WidthType.DXA },
            columnWidths: [4500, 4700],
            borders: {
              top: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
              bottom: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
              left: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
              right: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
              insideHorizontal: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
              insideVertical: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
            },
            rows: [
              // ─── ROW 1: Dates (left, top-aligned) | SURV+RECERT (right, bottom-aligned)
              new TableRow({
                children: [
                  // LEFT — 5 dates, top of cell
                  new TableCell({
                    borders: this.noBorder(),
                    verticalAlign: VerticalAlign.TOP,
                    width: { size: 4500, type: WidthType.DXA },
                    margins: { top: 80, bottom: 80, left: 0, right: 80 },
                    children: [
                      new Paragraph({
                        spacing: { before: 20, after: 20 },
                        children: [
                          new TextRun({
                            text: `EA   ${cert.ea_codes ?? cert.company?.accreditation ?? ''}`,
                            size: 20,
                          }),
                        ],
                      }),
                      new Paragraph({
                        spacing: { before: 20, after: 20 },
                        children: [
                          new TextRun({
                            text: `Certificate No: ${certNo}`,
                            size: 20,
                          }),
                        ],
                      }),
                      new Paragraph({
                        spacing: { before: 20, after: 20 },
                        children: [
                          new TextRun({
                            text: `Originally Registered: ${this.formatDate(cert.originally_registered)}`,
                            size: 20,
                          }),
                        ],
                      }),
                      new Paragraph({
                        spacing: { before: 20, after: 20 },
                        children: [
                          new TextRun({
                            text: `Latest Issue: ${this.formatDate(cert.issue_date)}`,
                            size: 20,
                          }),
                        ],
                      }),
                      new Paragraph({
                        spacing: { before: 20, after: 20 },
                        children: [
                          new TextRun({
                            text: `Valid up-to: ${this.formatDate(expireDate)}`,
                            size: 20,
                          }),
                        ],
                      }),
                    ],
                  }),
                  // RIGHT — SURV + RECERT, bottom of cell (aligns with last 2 left lines)
                  new TableCell({
                    borders: this.noBorder(),
                    verticalAlign: VerticalAlign.BOTTOM,
                    width: { size: 4700, type: WidthType.DXA },
                    margins: { top: 80, bottom: 80, left: 80, right: 0 },
                    children: [
                      ...(survAuditDate
                        ? [
                            new Paragraph({
                              spacing: { before: 20, after: 20 },
                              children: [
                                new TextRun({
                                  text: `SURV. AUDIT ON OR BEFORE: ${survAuditDate}`,
                                  size: 20,
                                }),
                              ],
                            }),
                          ]
                        : []),
                      ...(recertDate
                        ? [
                            new Paragraph({
                              spacing: { before: 20, after: 20 },
                              children: [
                                new TextRun({
                                  text: `RE-CERTIFICATION DUE ON: ${recertDate}`,
                                  size: 20,
                                }),
                              ],
                            }),
                          ]
                        : []),
                      // Fallback so cell isn't empty if no dates given
                      ...(!survAuditDate && !recertDate
                        ? [new Paragraph({ children: [new TextRun({ text: ' ' })] })]
                        : []),
                    ],
                  }),
                ],
              }),

              // ─── ROW 2: Empty (left) | Signature stack (right)
              new TableRow({
                children: [
                  // LEFT — empty filler
                  new TableCell({
                    borders: this.noBorder(),
                    width: { size: 4500, type: WidthType.DXA },
                    margins: { top: 80, bottom: 80, left: 0, right: 80 },
                    children: [
                      new Paragraph({ children: [new TextRun({ text: ' ' })] }),
                    ],
                  }),
                  // RIGHT — signature, line, "Quality Registrar Systems", QR (if any)
                  new TableCell({
                    borders: this.noBorder(),
                    verticalAlign: VerticalAlign.TOP,
                    width: { size: 4700, type: WidthType.DXA },
                    margins: { top: 200, bottom: 80, left: 80, right: 0 },
                    children: [
                      // Signature image (centered)
                      new Paragraph({
                        alignment: AlignmentType.CENTER,
                        spacing: { before: 0, after: 20 },
                        children: signatureBuffer
                          ? [
                              new ImageRun({
                                data: signatureBuffer,
                                transformation: { width: 160, height: 60 },
                                type: 'png',
                              }),
                            ]
                          : [new TextRun({ text: ' ', size: 40 })],
                      }),

                      // Signature line (paragraph border bottom)
                      new Paragraph({
                        alignment: AlignmentType.CENTER,
                        spacing: { before: 0, after: 40 },
                        indent: { left: 800, right: 800 },
                        border: {
                          bottom: {
                            style: BorderStyle.SINGLE,
                            size: 6,
                            color: '000000',
                            space: 1,
                          },
                        },
                        children: [new TextRun({ text: ' ', size: 4 })],
                      }),

                      // "Quality Registrar Systems" caption
                      new Paragraph({
                        alignment: AlignmentType.CENTER,
                        spacing: { before: 40, after: 100 },
                        children: [
                          new TextRun({
                            text: 'Quality Registrar Systems',
                            size: 20,
                          }),
                        ],
                      }),

                      // QR Code BELOW the label (only if cert has QR data)
                      ...(qrBuffer
                        ? [
                            new Paragraph({
                              alignment: AlignmentType.CENTER,
                              spacing: { before: 40, after: 20 },
                              children: [
                                new ImageRun({
                                  data: qrBuffer,
                                  transformation: { width: 90, height: 90 },
                                  type: 'png',
                                }),
                              ],
                            }),
                            new Paragraph({
                              alignment: AlignmentType.CENTER,
                              spacing: { before: 0, after: 0 },
                              children: [
                                new TextRun({
                                  text: 'Scan to verify',
                                  size: 14,
                                  color: '666666',
                                }),
                              ],
                            }),
                          ]
                        : []),
                    ],
                  }),
                ],
              }),
            ],
          }),
        ],
      },
    ];

    // ✅ Document-level Calibri default + native » bullet numbering
    const doc = new Document({
      styles: {
        default: {
          document: { run: { font: 'Calibri', size: 22 } },
        },
      },
      numbering: numberingConfig,
      sections,
    });

    const docxBuffer = await Packer.toBuffer(doc);

    const folder = this.ensureFolder();
    const safeCertNo = certNo.replace(/[^a-zA-Z0-9-]/g, '_');
    const fileName = `${safeCertNo}.docx`;
    const filePath = path.join(folder, fileName);

    fs.writeFileSync(filePath, docxBuffer);
    return `uploads/certificates/${fileName}`;
  }

  // ── Get file buffer for download ──────────────────────────────
  getFile(filePath: string): { buffer: Buffer; fileName: string } {
    const fullPath = path.join(process.cwd(), filePath);

    if (!fs.existsSync(fullPath)) {
      throw new Error('File not found. Please regenerate.');
    }

    const buffer = fs.readFileSync(fullPath);
    const fileName = path.basename(fullPath);

    return { buffer, fileName };
  }
}