const PDFDocument = require('pdfkit-table');
const fs = require('fs');
const path = require('path');
const saleModel = require('../models/saleModel');
const purchaseModel = require('../models/purchaseModel');
const db = require('../db/config');
const { sendInvoiceEmail } = require('../utils/mailer');

function numberToWords(n) {
  const a = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten',
    'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'];
  const b = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety'];
  if ((n = n.toString()).length > 9) return 'Overflow';
  const num = ('000000000' + n).substr(-9).match(/^(\d{2})(\d{2})(\d{2})(\d{3})$/);
  if (!num) return;
  let str = '';
  str += (num[1] != 0) ? (a[Number(num[1])] || b[num[1][0]] + ' ' + a[num[1][1]]) + ' Crore ' : '';
  str += (num[2] != 0) ? (a[Number(num[2])] || b[num[2][0]] + ' ' + a[num[2][1]]) + ' Lakh ' : '';
  str += (num[3] != 0) ? (a[Number(num[3])] || b[num[3][0]] + ' ' + a[num[3][1]]) + ' Thousand ' : '';
  str += (num[4] != 0) ? (a[Number(num[4])] || b[num[4][0]] + ' ' + a[num[4][1]]) + ' ' : '';
  return str + 'Taka Only';
}

async function renderStyledInvoice(type, data, res, filePath, logoPath, stampPath) {
  const doc = new PDFDocument({ size: 'A4', margin: 40 });
  const { invoiceId, partyName, partyEmail, address, reference, date, items, bank, summary } = data;

  doc.pipe(fs.createWriteStream(filePath));

  if (fs.existsSync(logoPath)) {
    doc.image(logoPath, 40, 40, { width: 60 });
  }

  doc
    .fontSize(18).text('MaanRishfa IT Solutions', 110, 40)
    .fontSize(10)
    .text('Mobile: +880-123456789', 110, 60)
    .text('Email: info@maanrishfa.com', 110, 75)
    .text('Address: Dhaka, Bangladesh', 110, 90);

  doc.moveDown(2);
  doc.fontSize(14).text(`${type} Invoice`, { align: 'center', underline: true });

  doc.moveDown(1);
  doc.fontSize(10).text(`Invoice No: ${invoiceId}`).text(`Date: ${date}`).text(`Reference: ${reference}`).text(`Payment Status: ${summary.status}`);
  doc.moveDown().text(`Bill To: ${partyName}`).text(`Address: ${address}`).moveDown();

  const rows = items.map((item, idx) => {
    const price = parseFloat(item.price || 0).toFixed(2);
    const qty = parseFloat(item.quantity || 0);
    const total = parseFloat(item.total || 0).toFixed(2);
    return [
      (idx + 1).toString(),
      item.name,
      '-',
      price,
      qty.toString(),
      '0.00',
      total
    ];
  });

  const table = {
    title: '',
    headers: ['Sl.No', 'Description', 'HSN/SAC', 'Unit Cost', 'Qty', 'Discount', 'Amount'],
    rows: rows,
    options: {
      columnSpacing: 5,
      padding: 5,
      width: doc.page.width - 80,
      prepareHeader: () => doc.font('Helvetica-Bold').fontSize(9),
      prepareRow: () => doc.font('Helvetica').fontSize(9)
    }
  };

  if (summary.status === 'Due') {
    doc.fontSize(50).fillColor('red').opacity(0.2)
      .rotate(45, { origin: [300, 350] })
      .text('DUE', 150, 300, { align: 'center' })
      .rotate(-45).opacity(1).fillColor('black');
  }

  await doc.table(table);

  const grandTotal = parseFloat(summary.total || 0).toFixed(2);
  doc.moveDown();
  doc.fontSize(10)
    .text(`Subtotal: ${grandTotal}`, { align: 'right' })
    .text(`Discount: 0.00`, { align: 'right' })
    .text(`Other Charges: 0.00`, { align: 'right' })
    .font('Helvetica-Bold')
    .text(`Grand Total: ${grandTotal} BDT`, { align: 'right' });

  doc.moveDown();
  doc.font('Helvetica')
    .text(`Amount in words: ${numberToWords(parseInt(grandTotal))}`, { align: 'left' })
    .text(`Bank: ${bank}`, { align: 'left' })
    .moveDown()
    .text(`Notes: Thank you for your business!`)
    .text(`Terms: Goods once sold will not be taken back.`)
    .text(`Signature`, 460);

  if (fs.existsSync(stampPath)) {
    doc.image(stampPath, 420, doc.y + 10, { width: 80 });
  }

  doc.end();

  doc.on('finish', async () => {
    await sendInvoiceEmail(
      partyEmail || 'default@example.com',
      `${type} Invoice from MaanRishfa IT`,
      `Dear ${partyName},

Please find your ${type.toLowerCase()} invoice attached.

Regards,
MaanRishfa IT`,
      filePath
    );
    res.download(filePath);
  });
}

exports.generateSaleInvoice = async (req, res) => {
  const saleId = req.params.id;
  const [saleData] = await saleModel.getById(saleId);
  const [items] = await saleModel.getItemsBySaleId(saleId);
  const [customer] = await db.query('SELECT name, address, email FROM customers WHERE id = ?', [saleData[0].customer_id]);

  const filePath = path.join(__dirname, `../invoices/sale_${saleId}.pdf`);
  const logoPath = path.join(__dirname, '../assets/logo.png');
  const stampPath = path.join(__dirname, '../assets/stamp.png');

  await renderStyledInvoice('Sales', {
    invoiceId: `SL${saleId.toString().padStart(4, '0')}`,
    partyName: customer[0]?.name || 'N/A',
    partyEmail: customer[0]?.email || 'default@example.com',
    address: customer[0]?.address || 'N/A',
    reference: 'N/A',
    date: new Date(saleData[0].sale_date).toLocaleDateString(),
    items,
    bank: 'City Bank Ltd.',
    summary: { total: saleData[0].total, status: saleData[0].status || 'Paid' }
  }, res, filePath, logoPath, stampPath);
};


exports.generatePurchaseInvoice = async (req, res) => {
  const purchaseId = req.params.id;
  const [purchaseData] = await purchaseModel.getById(purchaseId);
  const [items] = await purchaseModel.getItems(purchaseId);
  const [supplier] = await db.query('SELECT name, address, email FROM suppliers WHERE id = ?', [purchaseData[0].supplier_id]);

  const filePath = path.join(__dirname, `../invoices/purchase_${purchaseId}.pdf`);
  const logoPath = path.join(__dirname, '../assets/logo.png');
  const stampPath = path.join(__dirname, '../assets/stamp.png');

  await renderStyledInvoice('Purchase', {
    invoiceId: `PR${purchaseId.toString().padStart(4, '0')}`,
    partyName: supplier[0]?.name || 'N/A',
    partyEmail: supplier[0]?.email || 'default@example.com',
    address: supplier[0]?.address || 'N/A',
    reference: 'N/A',
    date: new Date(purchaseData[0].purchase_date).toLocaleDateString(),
    items,
    bank: 'City Bank Ltd.',
    summary: { total: purchaseData[0].total, status: purchaseData[0].status || 'Paid' }
  }, res, filePath, logoPath, stampPath);
};