const PDFDocument = require('pdfkit');
const path = require('path');
const fs = require('fs');
const db = require('../models');
const asyncHandler = require('../middlewares/asyncHandler');
const { sendError } = require('../utils/response');

const toNum = (value) => {
  const parsed = parseFloat(value);
  return Number.isFinite(parsed) ? parsed : 0;
};

const numberToWordsIndian = (num) => {
  const n = Math.floor(toNum(num));
  if (!n) return 'Zero';
  const ones = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'];
  const tens = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety'];
  const twoDigits = (x) => (x < 20 ? ones[x] : `${tens[Math.floor(x / 10)]}${x % 10 ? ` ${ones[x % 10]}` : ''}`.trim());
  const threeDigits = (x) => {
    const h = Math.floor(x / 100);
    const r = x % 100;
    return `${h ? `${ones[h]} Hundred` : ''}${h && r ? ' ' : ''}${r ? twoDigits(r) : ''}`.trim();
  };
  const crore = Math.floor(n / 10000000);
  const lakh = Math.floor((n % 10000000) / 100000);
  const thousand = Math.floor((n % 100000) / 1000);
  const rest = n % 1000;
  const parts = [];
  if (crore) parts.push(`${twoDigits(crore)} Crore`);
  if (lakh) parts.push(`${twoDigits(lakh)} Lakh`);
  if (thousand) parts.push(`${twoDigits(thousand)} Thousand`);
  if (rest) parts.push(threeDigits(rest));
  return parts.join(' ').trim();
};

exports.generatePDF = asyncHandler(async (req, res) => {
  const { id } = req.params;

  const invoice = await db.SalesInvoice.findByPk(id, {
    include: [
      { model: db.Company, as: 'company', attributes: ['id', 'name', 'legal_name', 'email', 'phone'] },
      { model: db.Plant, as: 'plant', attributes: ['id', 'name', 'email', 'phone'] },
      { model: db.BusinessPartner, as: 'customer', attributes: ['id', 'bp_number', 'name', 'legal_name'] },
      { model: db.BPAddress, as: 'customerAddress', attributes: ['address_line1', 'address_line2', 'pincode', 'email', 'phone', 'mobile'] },
      { model: db.BPGSTIN, as: 'customerGSTIN', attributes: ['gstin'] },
      { model: db.CustomerPO, as: 'customerPO', attributes: ['id', 'po_number'] },
      { model: db.Currency, as: 'currency', attributes: ['currency_code', 'currency_symbol'] },
      {
        model: db.SalesInvoiceItem,
        as: 'items',
        include: [
          { model: db.Material, as: 'material', attributes: ['material_number', 'description', 'hsn_code', 'sac_code'] },
          { model: db.UOM, as: 'uom', attributes: ['uom_code'] }
        ]
      }
    ],
    order: [[{ model: db.SalesInvoiceItem, as: 'items' }, 'item_number', 'ASC']]
  });

  if (!invoice) return sendError(res, 'Sales Invoice not found', 404);

  const printHeader = await db.PrintHeader.findOne({
    where: { company_id: invoice.company_id, status: 'ACTIVE' },
    order: [['id', 'DESC']]
  });

  const resolveFile = (relativePath) => {
    if (!relativePath) return null;
    const uploadPath = path.join(__dirname, '..', 'uploads', relativePath);
    if (fs.existsSync(uploadPath)) return uploadPath;
    const directPath = path.join(__dirname, '..', relativePath);
    if (fs.existsSync(directPath)) return directPath;
    return null;
  };

  const companyLogoPath = resolveFile(printHeader?.logo_path);
  const certLogoPath = resolveFile(printHeader?.quality_certification_logo_path);

  const fmtDate = (value) => {
    if (!value) return '';
    const d = new Date(value);
    if (Number.isNaN(d.getTime())) return '';
    const dd = String(d.getDate()).padStart(2, '0');
    const mm = String(d.getMonth() + 1).padStart(2, '0');
    return `${dd}/${mm}/${d.getFullYear()}`;
  };
  const fmtMoney = (value) => toNum(value).toFixed(2);
  const toMultilineByComma = (value) => String(value || '')
    .split(',')
    .map((part) => part.trim())
    .filter(Boolean)
    .join(',\n');

  const taxBase = Math.max(toNum(invoice.sub_total) - toNum(invoice.discount_amount), 0);
  const invoiceTaxAmount = toNum(invoice.tax_amount);
  const useIGST = String(invoice.gst_type || '').toUpperCase() === 'IGST';
  let cgstAmt = toNum(invoice.cgst_amount);
  let sgstAmt = toNum(invoice.sgst_amount);
  let igstAmt = toNum(invoice.igst_amount);
  if (useIGST) {
    igstAmt = igstAmt > 0 ? igstAmt : invoiceTaxAmount;
    cgstAmt = 0;
    sgstAmt = 0;
  } else {
    if (cgstAmt <= 0 && sgstAmt <= 0 && invoiceTaxAmount > 0) {
      cgstAmt = invoiceTaxAmount / 2;
      sgstAmt = invoiceTaxAmount / 2;
    }
    igstAmt = 0;
  }
  const cgstRate = taxBase > 0 ? (cgstAmt / taxBase) * 100 : 0;
  const sgstRate = taxBase > 0 ? (sgstAmt / taxBase) * 100 : 0;
  const igstRate = taxBase > 0 ? (igstAmt / taxBase) * 100 : 0;

  const doc = new PDFDocument({ margin: 30, size: 'A4' });
  const safeInvoiceNo = String(invoice.invoice_number || invoice.id).replace(/[^\w.-]+/g, '_');
  const safeCustomer = String(invoice.customer?.name || 'Customer').replace(/[^\w.-]+/g, '_');
  const filename = `Sales_Invoice_${safeInvoiceNo}_${safeCustomer}.pdf`;

  res.setHeader('Content-Type', 'application/pdf');
  res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
  doc.pipe(res);

  const pageWidth = 595.28;
  const margin = 30;
  const contentWidth = pageWidth - (margin * 2);
  const drawBorder = (x, y, w, h) => doc.rect(x, y, w, h).stroke('#000000');

  let y = margin;
  const headerHeight = 105;
  drawBorder(margin, y, contentWidth, headerHeight);

  const sidePadding = 4;
  const companyLogoBoxW = Math.min(200, contentWidth * 0.34);
  const companyLogoBoxH = headerHeight - 4;
  const certBoxW = Math.min(160, contentWidth * 0.26);
  const certBoxH = companyLogoBoxH;
  const logoX = margin + sidePadding;
  const logoY = y + 2;

  if (companyLogoPath) {
    try {
      doc.image(companyLogoPath, logoX, logoY, {
        cover: [companyLogoBoxW, companyLogoBoxH],
        align: 'center',
        valign: 'center'
      });
    } catch (_) {}
  }

  const leftBlockW = companyLogoBoxW + (sidePadding * 2);
  const rightBlockW = certBoxW + (sidePadding * 2);
  const centerX = margin + leftBlockW;
  const centerWidth = contentWidth - leftBlockW - rightBlockW;

  doc.fontSize(14).font('Helvetica-Bold').text(printHeader?.company_name || invoice.company?.name || 'Company Name', centerX, y + 5, { width: centerWidth, align: 'center' });
  if (printHeader?.former_name) {
    doc.fontSize(7).font('Helvetica-Oblique');
    doc.text(`(Formerly Known as ${printHeader.former_name})`, centerX, y + 20, { width: centerWidth, align: 'center' });
  }

  doc.fontSize(7).font('Helvetica');
  const addressY = printHeader?.former_name ? y + 32 : y + 22;
  if (printHeader?.address) {
    doc.text(printHeader.address, centerX, addressY, { width: centerWidth, align: 'center', lineGap: 1 });
  }
  const addressHeight = printHeader?.address
    ? doc.heightOfString(printHeader.address, { width: centerWidth, align: 'center', lineGap: 1 })
    : 0;
  let contactY = addressY + Math.max(10, addressHeight + 2);
  const headerEmail = printHeader?.email || invoice.company?.email || invoice.plant?.email || '';
  const headerPhone = printHeader?.phone || invoice.company?.phone || invoice.plant?.phone || '';
  const drawHeaderKV = (label, value) => {
    if (!value) return;
    const labelStr = String(label);
    const valueStr = String(value);
    doc.font('Helvetica-Bold').fontSize(7);
    const labelW = doc.widthOfString(labelStr);
    const colonStr = ' : ';
    const colonW = doc.widthOfString(colonStr);
    doc.font('Helvetica');
    const valueW = doc.widthOfString(valueStr);
    const x = centerX + Math.max(0, (centerWidth - (labelW + colonW + valueW)) / 2);
    doc.font('Helvetica-Bold').text(labelStr, x, contactY, { lineBreak: false });
    doc.text(colonStr, x + labelW, contactY, { lineBreak: false });
    doc.font('Helvetica').text(valueStr, x + labelW + colonW, contactY, { lineBreak: false });
    contactY += 9;
  };
  drawHeaderKV('Email', headerEmail);
  drawHeaderKV('Contact', headerPhone);
  drawHeaderKV('GSTIN', printHeader?.gstin || '');

  if (certLogoPath) {
    const certX = pageWidth - margin - certBoxW - sidePadding;
    const certY = y + 2;
    try {
      doc.image(certLogoPath, certX, certY, { fit: [certBoxW, certBoxH], align: 'center', valign: 'center' });
    } catch (_) {}
  }
  // Redraw top and bottom header lines so image white backgrounds do not break border continuity.
  doc.moveTo(margin, y).lineTo(margin + contentWidth, y).stroke();
  doc.moveTo(margin, y + headerHeight).lineTo(margin + contentWidth, y + headerHeight).stroke();
  y += headerHeight;

  drawBorder(margin, y, contentWidth, 20);
  doc.fontSize(12).font('Helvetica-Bold').text('TAX INVOICE', margin, y + 6, { width: contentWidth, align: 'center' });
  y += 20;

  const addressParts = [invoice.billing_address, invoice.customerAddress?.address_line1, invoice.customerAddress?.address_line2].filter(Boolean);
  const billingAddressText = toMultilineByComma(addressParts.join(', '));
  const shippingAddressText = toMultilineByComma(invoice.shipping_address);
  const customerGSTIN = invoice.customerGSTIN?.gstin || '';
  const quantityTotal = (invoice.items || []).reduce((s, it) => s + toNum(it.quantity), 0);
  const invoiceYear = new Date(invoice.invoice_date).getFullYear();
  const invoiceYearLabel = Number.isFinite(invoiceYear) ? `${invoiceYear}-${invoiceYear + 1}` : '';

  // Body like requested sample (header kept unchanged)
  const leftW = contentWidth * 0.52;
  const rightW = contentWidth - leftW;
  const rightX = margin + leftW;

  const leftTextW = leftW - 8;
  doc.font('Helvetica-Bold').fontSize(8);
  const companyTitleH = doc.heightOfString(`${printHeader?.company_name || invoice.company?.name || ''}  (${invoiceYearLabel})`, { width: leftTextW });
  doc.font('Helvetica').fontSize(7);
  const companyAddrH = doc.heightOfString(printHeader?.address || '', { width: leftTextW, lineGap: 1 });
  const shipAddrH = doc.heightOfString(shippingAddressText || billingAddressText, { width: leftTextW, lineGap: 1 });
  const billAddrH = doc.heightOfString(billingAddressText || shippingAddressText, { width: leftTextW, lineGap: 1 });

  const l1 = Math.max(74, 8 + companyTitleH + 4 + companyAddrH + 4 + 9 + 9 + 8);
  const l2 = Math.max(68, 8 + 10 + 10 + shipAddrH + 4 + 9 + 9 + 8);
  const l3 = Math.max(46, 8 + 10 + 10 + billAddrH + 8);
  const topHLeft = l1 + l2 + l3;
  const topHRight = 8 * 22;
  const topH = Math.max(180, topHLeft, topHRight);

  drawBorder(margin, y, leftW, topH);
  drawBorder(rightX, y, rightW, topH);

  // Left: company/consignee/buyer style blocks
  doc.moveTo(margin, y + l1).lineTo(margin + leftW, y + l1).stroke();
  doc.moveTo(margin, y + l1 + l2).lineTo(margin + leftW, y + l1 + l2).stroke();
  let ly = y + 4;
  doc.font('Helvetica-Bold').fontSize(8).text(`${printHeader?.company_name || invoice.company?.name || ''}  (${invoiceYearLabel})`, margin + 4, ly, { width: leftW - 8 });
  ly += companyTitleH + 2;
  doc.font('Helvetica').fontSize(7).text(printHeader?.address || '', margin + 4, ly, { width: leftW - 8, lineGap: 1 });
  ly += companyAddrH + 4;
  doc.text(`GSTIN/UIN : ${printHeader?.gstin || ''}`, margin + 4, ly, { width: leftW - 8 }); ly += 9;
  doc.text(`State Name : Tamil Nadu, Code : 33`, margin + 4, ly, { width: leftW - 8 });

  ly = y + l1 + 4;
  doc.font('Helvetica-Bold').fontSize(7).text('Consignee (Ship to)', margin + 4, ly, { width: leftW - 8 }); ly += 10;
  doc.font('Helvetica-Bold').text((invoice.customer?.name || '').toUpperCase(), margin + 4, ly, { width: leftW - 8 }); ly += 10;
  doc.font('Helvetica').text(shippingAddressText || billingAddressText, margin + 4, ly, { width: leftW - 8, lineGap: 1 }); ly += shipAddrH + 4;
  doc.text(`GSTIN/UIN : ${customerGSTIN}`, margin + 4, ly, { width: leftW - 8 }); ly += 9;
  doc.text(`State Name : Tamil Nadu, Code : 33`, margin + 4, ly, { width: leftW - 8 });

  ly = y + l1 + l2 + 4;
  doc.font('Helvetica-Bold').fontSize(7).text('Buyer (Bill to)', margin + 4, ly, { width: leftW - 8 }); ly += 10;
  doc.font('Helvetica-Bold').text((invoice.customer?.name || '').toUpperCase(), margin + 4, ly, { width: leftW - 8 }); ly += 10;
  doc.font('Helvetica').text(billingAddressText || shippingAddressText, margin + 4, ly, { width: leftW - 8, lineGap: 1 });

  // Right: key-value matrix
  const metaRows = [
    ['Invoice No.', invoice.invoice_number || '', 'e-Way Bill No.', ''],
    ['Delivery Note', invoice.reference_invoice_no || '', 'Dated', fmtDate(invoice.delivery_note_date || invoice.invoice_date)],
    ['Reference No. & Date.', invoice.reference_invoice_no || '', 'Other References', invoice.other_references || ''],
    ["Buyer's Order No.", invoice.customer_po_no || invoice.customerPO?.po_number || '', 'Dated', fmtDate(invoice.invoice_date)],
    ['Dispatch Doc No.', invoice.sales_order_no || '', 'Delivery Note Date', fmtDate(invoice.delivery_note_date || invoice.due_date)],
    ['Dispatched through', invoice.transport_details || '', 'Destination', invoice.place_of_supply || ''],
    ['Bill of Lading/LR-RR No.', '', 'Motor Vehicle No.', invoice.motor_vehicle_no || ''],
    ['Mode/Terms of Payment', invoice.mode_terms_of_payment || invoice.payment_terms || '', 'Terms of Delivery', invoice.terms_of_delivery || 'By Road']
  ];
  const rowH = topH / metaRows.length;
  const halfW = rightW / 2;
  for (let i = 0; i < metaRows.length; i += 1) {
    const yy = y + i * rowH;
    doc.moveTo(rightX, yy).lineTo(rightX + rightW, yy).stroke();
    doc.moveTo(rightX + halfW, yy).lineTo(rightX + halfW, yy + rowH).stroke();
    const [l1k, l1v, l2k, l2v] = metaRows[i];
    doc.font('Helvetica-Bold').fontSize(6.4).text(l1k, rightX + 3, yy + 3, { width: 70, lineBreak: false, ellipsis: true });
    doc.font('Helvetica').fontSize(6.6).text(String(l1v || ''), rightX + 74, yy + 3, { width: halfW - 77, lineBreak: false, ellipsis: true });
    if (l2k) {
      doc.font('Helvetica-Bold').fontSize(6.4).text(l2k, rightX + halfW + 3, yy + 3, { width: 70, lineBreak: false, ellipsis: true });
      doc.font('Helvetica').fontSize(6.6).text(String(l2v || ''), rightX + halfW + 74, yy + 3, { width: halfW - 77, lineBreak: false, ellipsis: true });
    }
  }
  doc.moveTo(rightX, y + topH).lineTo(rightX + rightW, y + topH).stroke();
  y += topH;

  // Item table
  const cols = [
    { label: 'Sl No.', w: 18, align: 'center' },
    { label: 'Description of Goods', w: 155, align: 'left' },
    { label: 'HSN/SAC', w: 58, align: 'center' },
    { label: 'GST Rate', w: 44, align: 'center' },
    { label: 'Quantity', w: 66, align: 'right' },
    { label: 'Rate', w: 66, align: 'right' },
    { label: 'per', w: 36, align: 'center' },
    { label: 'Disc. %', w: 50, align: 'right' },
    { label: 'Amount', w: contentWidth - 493, align: 'right' }
  ];
  const headerRowH = 32;
  drawBorder(margin, y, contentWidth, headerRowH);
  let cx = margin;
  cols.forEach((c, idx) => {
    if (idx > 0) doc.moveTo(cx, y).lineTo(cx, y + headerRowH).stroke();
    doc.font('Helvetica-Bold').fontSize(7).text(c.label, cx + 2, y + 6, { width: c.w - 4, align: c.align, lineBreak: false, ellipsis: true });
    cx += c.w;
  });
  y += headerRowH;

  (invoice.items || []).forEach((it, idx) => {
    const rowHeight = 92;
    drawBorder(margin, y, contentWidth, rowHeight);
    let rx = margin;
    const itemDesc = `${it.material?.material_number || ''}, ${it.material?.description || it.description || ''}`.trim();
    const values = [
      String(idx + 1),
      itemDesc,
      it.hsn_code || it.material?.hsn_code || it.material?.sac_code || '',
      `${fmtMoney(it.tax_rate)} %`,
      `${fmtMoney(it.quantity)} ${it.uom?.uom_code || ''}`.trim(),
      fmtMoney(it.unit_price),
      it.uom?.uom_code || '',
      fmtMoney(it.discount_percentage),
      fmtMoney(it.total_amount)
    ];
    cols.forEach((c, cIdx) => {
      if (cIdx > 0) doc.moveTo(rx, y).lineTo(rx, y + rowHeight).stroke();
      doc.font(cIdx === 1 || cIdx === 4 || cIdx === 8 ? 'Helvetica-Bold' : 'Helvetica').fontSize(7).text(values[cIdx], rx + 2, y + 6, { width: c.w - 4, align: c.align, lineBreak: false, ellipsis: true });
      rx += c.w;
    });
    // tax split lines per item (Output GST style)
    const amountX = margin + cols.slice(0, 8).reduce((s, c) => s + c.w, 0);
    const lineQty = toNum(it.quantity);
    const lineRate = toNum(it.unit_price);
    const lineDiscPct = toNum(it.discount_percentage);
    const lineTaxable = Math.max((lineQty * lineRate) - ((lineQty * lineRate * lineDiscPct) / 100), 0);
    const lineTaxRate = toNum(it.tax_rate);
    const lineCGSTRate = useIGST ? 0 : (toNum(it.cgst_rate) || (lineTaxRate / 2));
    const lineSGSTRate = useIGST ? 0 : (toNum(it.sgst_rate) || (lineTaxRate / 2));
    const lineIGSTRate = useIGST ? (toNum(it.igst_rate) || lineTaxRate) : 0;
    const lineCGSTAmt = useIGST ? 0 : (toNum(it.cgst_amount) || ((lineTaxable * lineCGSTRate) / 100));
    const lineSGSTAmt = useIGST ? 0 : (toNum(it.sgst_amount) || ((lineTaxable * lineSGSTRate) / 100));
    const lineIGSTAmt = useIGST ? (toNum(it.igst_amount) || ((lineTaxable * lineIGSTRate) / 100)) : 0;

    doc.font('Helvetica-BoldOblique').fontSize(7);
    if (!useIGST) {
      doc.text(`Output CGST ${fmtMoney(lineCGSTRate)}%`, margin + 70, y + 40, { width: 120, align: 'left' });
      doc.text(`Output SGST ${fmtMoney(lineSGSTRate)}%`, margin + 70, y + 54, { width: 120, align: 'left' });
      doc.font('Helvetica').text(fmtMoney(lineCGSTAmt), amountX + 2, y + 40, { width: cols[8].w - 4, align: 'right' });
      doc.text(fmtMoney(lineSGSTAmt), amountX + 2, y + 54, { width: cols[8].w - 4, align: 'right' });
    } else if (lineIGSTAmt > 0) {
      doc.text(`Output IGST ${fmtMoney(lineIGSTRate)}%`, margin + 70, y + 47, { width: 120, align: 'left' });
      doc.font('Helvetica').text(fmtMoney(lineIGSTAmt), amountX + 2, y + 47, { width: cols[8].w - 4, align: 'right' });
    }
    y += rowHeight;
  });

  const totalRowH = 18;
  drawBorder(margin, y, contentWidth, totalRowH);
  doc.font('Helvetica-Bold').fontSize(7).text('Total', margin + cols[0].w + cols[1].w - 20, y + 5, { width: 40, align: 'right' });
  const qtyX = margin + cols.slice(0, 4).reduce((s, c) => s + c.w, 0);
  doc.text(`${fmtMoney(quantityTotal)} ${invoice.items?.[0]?.uom?.uom_code || ''}`.trim(), qtyX + 2, y + 5, { width: cols[4].w - 4, align: 'right' });
  doc.text(fmtMoney(invoice.total_amount), margin + contentWidth - cols[8].w + 2, y + 5, { width: cols[8].w - 4, align: 'right', lineBreak: false, ellipsis: true });
  let vx = margin;
  cols.forEach((c, idx) => { if (idx > 0) doc.moveTo(vx, y).lineTo(vx, y + totalRowH).stroke(); vx += c.w; });
  y += totalRowH;

  const amountWords = `INR ${numberToWordsIndian(invoice.total_amount)} Only`;
  drawBorder(margin, y, contentWidth, 34);
  doc.font('Helvetica').fontSize(7).text('Amount Chargeable (in words)', margin + 4, y + 4, { width: contentWidth - 8 });
  doc.font('Helvetica-Bold').fontSize(10).text(amountWords, margin + 4, y + 14, { width: contentWidth - 8 });
  doc.font('Helvetica-Bold').fontSize(8).text('E. & O.E', margin + contentWidth - 45, y + 22, { width: 40, align: 'right' });
  y += 34;

  // Tax summary matrix
  const taxH = 84;
  drawBorder(margin, y, contentWidth, taxH);
  const taxCols = [0.26, 0.18, 0.08, 0.12, 0.08, 0.12, 0.16].map((r) => r * contentWidth);
  const taxRowY1 = y + 16;
  const taxRowY2 = y + 30;
  const taxRowY3 = y + 50;
  const taxRowY4 = y + 68;

  let tx = margin;
  for (let i = 1; i < taxCols.length; i += 1) {
    tx += taxCols[i - 1];
    // Keep CGST/SGST group headers merged in first row by avoiding full-height
    // center dividers for Rate/Amount split lines.
    if (i === 3 || i === 5) {
      doc.moveTo(tx, taxRowY1).lineTo(tx, y + taxH).stroke();
    } else {
      doc.moveTo(tx, y).lineTo(tx, y + taxH).stroke();
    }
  }

  doc.moveTo(margin, taxRowY1).lineTo(margin + contentWidth, taxRowY1).stroke();
  doc.moveTo(margin, taxRowY2).lineTo(margin + contentWidth, taxRowY2).stroke();
  doc.moveTo(margin, taxRowY3).lineTo(margin + contentWidth, taxRowY3).stroke();
  doc.moveTo(margin, taxRowY4).lineTo(margin + contentWidth, taxRowY4).stroke();

  const colX = [];
  let runningX = margin;
  taxCols.forEach((w) => {
    colX.push(runningX);
    runningX += w;
  });

  // Top group headers
  doc.font('Helvetica-Bold').fontSize(7);
  doc.text('Taxable\nValue', colX[1] + 2, y + 2, { width: taxCols[1] - 4, align: 'right' });
  doc.text('CGST', colX[2] + 2, y + 4, { width: taxCols[2] + taxCols[3] - 4, align: 'center', lineBreak: false });
  doc.text('SGST/UTGST', colX[4] + 2, y + 4, { width: taxCols[4] + taxCols[5] - 4, align: 'center', lineBreak: false });
  doc.text('Total\nTax Amount', colX[6] + 2, y + 2, { width: taxCols[6] - 4, align: 'right' });

  // Sub headers for tax groups
  doc.font('Helvetica').fontSize(7);
  doc.text('Rate', colX[2] + 2, taxRowY1 + 3, { width: taxCols[2] - 4, align: 'center', lineBreak: false });
  doc.text('Amount', colX[3] + 2, taxRowY1 + 3, { width: taxCols[3] - 4, align: 'center', lineBreak: false });
  doc.text('Rate', colX[4] + 2, taxRowY1 + 3, { width: taxCols[4] - 4, align: 'center', lineBreak: false });
  doc.text('Amount', colX[5] + 2, taxRowY1 + 3, { width: taxCols[5] - 4, align: 'center', lineBreak: false });

  const totalTaxAmount = cgstAmt + sgstAmt + igstAmt;

  // Detail row
  doc.font('Helvetica').fontSize(7);
  doc.text(fmtMoney(taxBase), colX[1] + 2, taxRowY2 + 5, { width: taxCols[1] - 4, align: 'right', lineBreak: false, ellipsis: true });
  doc.text(`${fmtMoney(cgstRate)}%`, colX[2] + 2, taxRowY2 + 5, { width: taxCols[2] - 4, align: 'right', lineBreak: false, ellipsis: true });
  doc.text(fmtMoney(cgstAmt), colX[3] + 2, taxRowY2 + 5, { width: taxCols[3] - 4, align: 'right', lineBreak: false, ellipsis: true });
  doc.text(`${fmtMoney(sgstRate)}%`, colX[4] + 2, taxRowY2 + 5, { width: taxCols[4] - 4, align: 'right', lineBreak: false, ellipsis: true });
  doc.text(fmtMoney(sgstAmt), colX[5] + 2, taxRowY2 + 5, { width: taxCols[5] - 4, align: 'right', lineBreak: false, ellipsis: true });
  doc.text(fmtMoney(totalTaxAmount), colX[6] + 2, taxRowY2 + 5, { width: taxCols[6] - 4, align: 'right', lineBreak: false, ellipsis: true });

  // Total row
  doc.font('Helvetica-Bold').fontSize(7.5);
  doc.text('Total:', colX[0] + 4, taxRowY3 + 5, { width: taxCols[0] + taxCols[1] - 8, align: 'center', lineBreak: false });
  doc.text(fmtMoney(taxBase), colX[1] + 2, taxRowY3 + 5, { width: taxCols[1] - 4, align: 'right', lineBreak: false, ellipsis: true });
  doc.text(fmtMoney(cgstAmt), colX[3] + 2, taxRowY3 + 5, { width: taxCols[3] - 4, align: 'right', lineBreak: false, ellipsis: true });
  doc.text(fmtMoney(sgstAmt), colX[5] + 2, taxRowY3 + 5, { width: taxCols[5] - 4, align: 'right', lineBreak: false, ellipsis: true });
  doc.text(fmtMoney(totalTaxAmount), colX[6] + 2, taxRowY3 + 5, { width: taxCols[6] - 4, align: 'right', lineBreak: false, ellipsis: true });
  y += taxH;

  drawBorder(margin, y, contentWidth, 24);
  doc.font('Helvetica').fontSize(8).text('Tax Amount (in words) :', margin + 4, y + 7, { width: 120 });
  doc.font('Helvetica-Bold').text(`INR ${numberToWordsIndian(cgstAmt + sgstAmt + igstAmt)} Only`, margin + 128, y + 7, { width: contentWidth - 132 });
  y += 24;

  const bottomH = 78;
  drawBorder(margin, y, contentWidth, bottomH);
  const splitX = margin + contentWidth * 0.5;
  const bankAccountHolder = invoice.bank_account_holder_name || printHeader?.company_name || invoice.company?.name || '-';
  const bankName = invoice.bank_name || 'State Bank of India';
  const bankAccountNo = invoice.bank_account_no || '-';
  const bankBranch = invoice.bank_branch || '-';
  const bankIfsc = invoice.bank_ifsc_code || '-';
  doc.moveTo(splitX, y).lineTo(splitX, y + bottomH).stroke();
  doc.font('Helvetica-Bold').fontSize(7).text(`Remarks:\n${invoice.invoice_number || ''}`, margin + 4, y + 4, { width: splitX - margin - 8 });
  doc.font('Helvetica').text('Declaration\nWe declare that this invoice shows the actual price of the goods described and that all particulars are true and correct.', margin + 4, y + 28, { width: splitX - margin - 8 });
  doc.font('Helvetica').text("Company's Bank Details\nA/c Holder's Name :\nBank Name        :\nA/c No.          :\nBranch & IFS Code:", splitX + 4, y + 4, { width: contentWidth * 0.25 });
  doc.font('Helvetica-Bold').text(`${bankAccountHolder}\n${bankName}\n${bankAccountNo}\n${bankBranch} / ${bankIfsc}`, splitX + 100, y + 14, { width: contentWidth * 0.25 - 8 });
  doc.font('Helvetica-Bold').text(`for ${printHeader?.company_name || invoice.company?.name || ''}`, splitX + 4, y + bottomH - 18, { width: contentWidth * 0.5 - 8, align: 'right' });
  y += bottomH;

  drawBorder(margin, y, contentWidth, 22);
  doc.font('Helvetica').fontSize(8).text("Customer's Seal and Signature", margin + 4, y + 7, { width: contentWidth * 0.5 - 8 });
  doc.font('Helvetica').text('Authorised Signatory', margin + contentWidth * 0.5 + 4, y + 7, { width: contentWidth * 0.5 - 8, align: 'right' });
  y += 22;
  doc.font('Helvetica').fontSize(8).text('This is a Computer Generated Invoice', margin, y + 8, { width: contentWidth, align: 'center' });

  doc.end();
});
