const PDFDocument = require('pdfkit');
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 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 amountToWords = (num) => {
  const n = Math.floor(toNum(num));
  if (n === 0) return 'Zero Rupees Only';
  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 belowThousand = (x) => {
    let s = '';
    const hundred = Math.floor(x / 100);
    const rem = x % 100;
    if (hundred > 0) s += `${ones[hundred]} Hundred`;
    if (rem > 0) {
      if (s) s += ' ';
      if (rem < 20) s += ones[rem];
      else s += `${tens[Math.floor(rem / 10)]}${rem % 10 ? ` ${ones[rem % 10]}` : ''}`;
    }
    return s.trim();
  };
  let value = n;
  const parts = [];
  const crore = Math.floor(value / 10000000);
  if (crore) { parts.push(`${belowThousand(crore)} Crore`); value %= 10000000; }
  const lakh = Math.floor(value / 100000);
  if (lakh) { parts.push(`${belowThousand(lakh)} Lakh`); value %= 100000; }
  const thousand = Math.floor(value / 1000);
  if (thousand) { parts.push(`${belowThousand(thousand)} Thousand`); value %= 1000; }
  if (value) parts.push(belowThousand(value));
  return `${parts.join(' ').trim()} Rupees Only`;
};

exports.generatePDF = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const payment = await db.VendorPayment.findByPk(id, {
    include: [
      { model: db.Company, as: 'company', attributes: ['id', 'name', 'email', 'phone'] },
      { model: db.Plant, as: 'plant', attributes: ['id', 'name'] },
      {
        model: db.BusinessPartner,
        as: 'vendor',
        attributes: ['id', 'bp_number', 'name', 'phone_numbers'],
        include: [
          { model: db.BPAddress, as: 'addresses', attributes: ['phone', 'mobile', 'email', 'status', 'is_default'], required: false },
          { model: db.BPGSTIN, as: 'gstins', attributes: ['gstin', 'status', 'is_default'], required: false }
        ]
      },
      {
        model: db.VendorInvoice,
        as: 'purchaseInvoice',
        attributes: ['id', 'invoice_number', 'vendor_invoice_number', 'invoice_date', 'net_payable', 'total_amount'],
        include: [
          {
            model: db.VendorInvoiceItem,
            as: 'items',
            attributes: ['line_number', 'description', 'quantity'],
            include: [{ model: db.Material, as: 'material', attributes: ['material_number', 'description'], required: false }],
            required: false
          }
        ],
        required: false
      },
      { model: db.VendorPaymentItem, as: 'items', required: false }
    ]
  });
  if (!payment) return sendError(res, 'Vendor payment not found', 404);

  let paymentModeRows = [];
  try {
    paymentModeRows = await db.PaymentMode.findAll({
      where: { company_id: payment.company_id, status: 'ACTIVE' },
      attributes: ['mode_code', 'mode_name'],
      order: [['mode_name', 'ASC']]
    });
  } catch (_) {
    paymentModeRows = [];
  }

  const doc = new PDFDocument({ margin: 30, size: 'A4' });
  const safeNo = String(payment.payment_no || payment.id).replace(/[^\w.-]+/g, '_');
  const safeVendor = String(payment.vendor?.name || 'Vendor').replace(/[^\w.-]+/g, '_');
  const filename = `Vendor_Payment_Receipt_${safeNo}_${safeVendor}.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');
  const drawKeyValue = ({ x, y, keyWidth, valueWidth, label, value, fontSize = 8, lineHeight = 10 }) => {
    doc.font('Helvetica-Bold').fontSize(fontSize).text(label, x, y, { width: keyWidth, align: 'left' });
    doc.font('Helvetica').fontSize(fontSize).text(':', x + keyWidth + 2, y, { width: 8, align: 'center' });
    doc.font('Helvetica').fontSize(fontSize).text(value || '', x + keyWidth + 12, y, { width: valueWidth });
    return lineHeight;
  };
  const pickPrimaryAddress = (addresses = []) => {
    const active = (addresses || []).filter((a) => String(a?.status || '').toUpperCase() !== 'INACTIVE');
    return active.find((a) => !!a?.is_default) || active[0] || addresses[0] || null;
  };
  const pickPrimaryGSTIN = (gstins = []) => {
    const active = (gstins || []).filter((g) => String(g?.status || '').toUpperCase() !== 'INACTIVE');
    return active.find((g) => !!g?.is_default) || active[0] || gstins[0] || null;
  };

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

  const leftW = contentWidth * 0.56;
  const rightW = contentWidth - leftW;
  const primaryAddress = pickPrimaryAddress(payment.vendor?.addresses || []);
  const primaryGSTIN = pickPrimaryGSTIN(payment.vendor?.gstins || []);
  const vendorContact = primaryAddress?.mobile || primaryAddress?.phone || payment.vendor?.phone_numbers || '';
  const vendorEmail = primaryAddress?.email || '';
  const vendorGSTIN = primaryGSTIN?.gstin || '';
  const leftRows = [
    ['Vendor', payment.vendor?.name || ''],
    ['Vendor Code', payment.vendor?.bp_number || ''],
    ['Contact', vendorContact],
    ['Vendor Email', vendorEmail],
    ['Vendor GSTIN', vendorGSTIN]
  ];
  const rightRows = [
    ['Payment No', payment.payment_no || ''],
    ['Payment Date', fmtDate(payment.payment_date)],
    ['Invoice No', payment.purchaseInvoice?.invoice_number || ''],
    ['Vendor Invoice No', payment.purchaseInvoice?.vendor_invoice_number || ''],
    ['Invoice Date', fmtDate(payment.purchaseInvoice?.invoice_date)]
  ];
  const detailH = Math.max(leftRows.length, rightRows.length) * 10 + 10;
  drawBorder(margin, y, contentWidth, detailH);
  doc.moveTo(margin + leftW, y).lineTo(margin + leftW, y + detailH).stroke();
  let ly = y + 5;
  leftRows.forEach(([k, v]) => { ly += drawKeyValue({ x: margin + 6, y: ly, keyWidth: 96, valueWidth: leftW - 118, label: k, value: v }); });
  let ry = y + 5;
  rightRows.forEach(([k, v]) => { ry += drawKeyValue({ x: margin + leftW + 5, y: ry, keyWidth: 96, valueWidth: rightW - 110, label: k, value: v }); });
  y += detailH;

  drawBorder(margin, y, contentWidth, 26);
  doc.font('Helvetica-Bold').fontSize(8).text('Invoice Amount', margin + 6, y + 5);
  doc.font('Helvetica').fontSize(8).text(toNum(payment.invoice_total).toFixed(2), margin + 90, y + 5, { width: 70, align: 'right' });
  doc.font('Helvetica-Bold').fontSize(8).text('Paid Amount', margin + 190, y + 5);
  doc.font('Helvetica').fontSize(8).text(toNum(payment.paid_amount).toFixed(2), margin + 255, y + 5, { width: 70, align: 'right' });
  doc.font('Helvetica-Bold').fontSize(8).text('Balance Amount', margin + 360, y + 5);
  doc.font('Helvetica').fontSize(8).text(toNum(payment.balance_amount).toFixed(2), margin + 450, y + 5, { width: 80, align: 'right' });
  y += 26;

  const invoiceItems = payment.purchaseInvoice?.items || [];
  if (invoiceItems.length) {
    const cols = [{ label: 'No', w: 26 }, { label: 'Item', w: contentWidth - 106 }, { label: 'Qty', w: 80 }];
    drawBorder(margin, y, contentWidth, 20);
    let hx = margin;
    cols.forEach((c, idx) => {
      if (idx > 0) doc.moveTo(hx, y).lineTo(hx, y + 20).stroke();
      doc.font('Helvetica-Bold').fontSize(7).text(c.label, hx + 2, y + 6, { width: c.w - 4, align: 'center' });
      hx += c.w;
    });
    y += 20;
    invoiceItems.slice(0, 5).forEach((it, idx) => {
      drawBorder(margin, y, contentWidth, 18);
      const itemText = `${it.material?.material_number || ''} ${it.description || it.material?.description || ''}`.trim();
      const vals = [String(idx + 1), itemText, toNum(it.quantity).toFixed(3)];
      let rx = margin;
      cols.forEach((c, cIdx) => {
        if (cIdx > 0) doc.moveTo(rx, y).lineTo(rx, y + 18).stroke();
        doc.font('Helvetica').fontSize(7).text(vals[cIdx], rx + 2, y + 5, { width: c.w - 4, align: cIdx === 0 ? 'right' : (cIdx === 2 ? 'right' : 'left') });
        rx += c.w;
      });
      y += 18;
    });
  }

  const items = Array.isArray(payment.items) && payment.items.length > 0 ? payment.items : [{
    payment_mode: payment.payment_mode,
    amount: payment.paid_amount
  }];
  const fallbackModes = ['BANK', 'UPI', 'CASH', 'CHEQUE', 'NEFT'];
  const configuredModes = (paymentModeRows || []).map((pm) => String(pm.mode_code || '').toUpperCase()).filter(Boolean);
  const allModes = Array.from(new Set([...(configuredModes.length ? configuredModes : fallbackModes), ...fallbackModes]));
  const amountByMode = new Map();
  items.forEach((it) => {
    const mode = String(it.payment_mode || '').toUpperCase();
    amountByMode.set(mode, toNum(amountByMode.get(mode)) + toNum(it.amount));
  });
  const paymentLines = allModes.map((mode) => `${mode} : ${toNum(amountByMode.get(mode)).toFixed(2)}`);
  const paymentInfoH = Math.max(40, 20 + (paymentLines.length * 10));
  const paymentLeftW = contentWidth / 2;
  const paymentRightW = contentWidth - paymentLeftW;
  drawBorder(margin, y, contentWidth, paymentInfoH);
  doc.moveTo(margin + paymentLeftW, y).lineTo(margin + paymentLeftW, y + paymentInfoH).stroke();
  doc.font('Helvetica-Bold').fontSize(8).text('Payment Modes', margin + 5, y + 8, { width: 88, align: 'left' });
  doc.font('Helvetica').fontSize(8).text(':', margin + 92, y + 8, { width: 8, align: 'center' });
  paymentLines.forEach((line, idx) => {
    doc.font('Helvetica').fontSize(8).text(line, margin + 105, y + 18 + (idx * 10), { width: paymentLeftW - 110, align: 'left' });
  });
  doc.font('Helvetica-Bold').fontSize(8).text('Amount in Words', margin + paymentLeftW + 5, y + 13, { width: 95, align: 'right' });
  doc.font('Helvetica').fontSize(8).text(`: ${amountToWords(payment.paid_amount)}`, margin + paymentLeftW + 104, y + 13, { width: paymentRightW - 109 });
  y += paymentInfoH;

  drawBorder(margin, y, contentWidth / 2, 44);
  drawBorder(margin + (contentWidth / 2), y, contentWidth / 2, 44);
  doc.font('Helvetica-Bold').fontSize(8).text('Authorized Signature', margin + 8, y + 30, { width: contentWidth / 2 - 16 });
  doc.font('Helvetica-Bold').fontSize(8).text('Vendor Signature', margin + (contentWidth / 2) + 8, y + 30, { width: contentWidth / 2 - 16 });

  doc.end();
});

