const PDFDocument = require('pdfkit');
const Papa = require('papaparse');
const writeXlsxFile = require('write-excel-file/node');

function formatValue(value, format) {
  if (value === null || value === undefined || value === '') return '';
  if (format === 'currency') return Number(value).toLocaleString('en-US', { style: 'currency', currency: 'USD' });
  if (format === 'number') return Number(value).toLocaleString('en-US');
  return String(value);
}

function tableMatrix(report) {
  const header = report.columns.map((column) => column.label);
  const body = report.rows.map((row) => report.columns.map((column) => {
    const value = row[column.key];
    return column.format === 'currency' || column.format === 'number' ? Number(value || 0) : (value ?? '');
  }));
  return { header, body };
}

function totalsRow(report) {
  if (!report.totals || !Object.keys(report.totals).length) return null;
  return report.columns.map((column, index) => {
    if (index === 0) return 'Totals';
    if (Object.prototype.hasOwnProperty.call(report.totals, column.key)) return report.totals[column.key];
    return '';
  });
}

function exportCsv(report) {
  const { header, body } = tableMatrix(report);
  const totals = totalsRow(report);
  const rows = totals ? [...body, totals] : body;
  return {
    contentType: 'text/csv',
    body: Papa.unparse([header, ...rows])
  };
}

async function exportXlsx(report) {
  const { header } = tableMatrix(report);
  const totals = totalsRow(report);
  const data = [
    header.map((label) => ({ value: label, fontWeight: 'bold' })),
    ...report.rows.map((row) => report.columns.map((column) => {
      const value = row[column.key];
      if (column.format === 'currency' || column.format === 'number') {
        return { type: Number, value: Number(value || 0), format: column.format === 'currency' ? '#,##0.00' : '#,##0' };
      }
      return { value: value === null || value === undefined ? '' : String(value) };
    }))
  ];
  if (totals) {
    data.push(totals.map((value, index) => {
      if (index === 0) return { value: 'Totals', fontWeight: 'bold' };
      return typeof value === 'number'
        ? { type: Number, value, format: '#,##0.00', fontWeight: 'bold' }
        : { value: String(value || ''), fontWeight: 'bold' };
    }));
  }
  return {
    contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    body: await writeXlsxFile(data).toBuffer()
  };
}

function exportPdf(report) {
  const doc = new PDFDocument({ margin: 36, size: 'LETTER', layout: 'landscape' });
  const chunks = [];
  doc.on('data', (chunk) => chunks.push(chunk));

  doc.fontSize(16).text(report.title || 'DepreCore report');
  doc.fontSize(9).fillColor('#555').text(
    `Generated ${new Date(report.generatedAt || Date.now()).toLocaleString()}` +
    (report.options ? `  ·  ${Object.entries(report.options).filter(([, v]) => v !== null && v !== undefined && v !== '').map(([k, v]) => `${k}: ${v}`).join('  ·  ')}` : '')
  );
  if (report.meta && report.meta.note) doc.moveDown(0.3).fontSize(8).fillColor('#777').text(report.meta.note);
  doc.fillColor('#000').moveDown(0.6);

  const pageWidth = doc.page.width - 72;
  const columns = report.columns;
  const colWidth = pageWidth / columns.length;
  const drawRow = (cells, options = {}) => {
    const y = doc.y;
    doc.fontSize(options.bold ? 8.5 : 8);
    cells.forEach((cell, index) => {
      const column = columns[index];
      const align = column.format === 'currency' || column.format === 'number' ? 'right' : 'left';
      doc.text(String(cell ?? ''), 36 + index * colWidth, y, { width: colWidth - 6, align, ellipsis: true });
    });
    doc.moveDown(0.2);
    if (doc.y > doc.page.height - 48) doc.addPage();
  };

  drawRow(columns.map((column) => column.label), { bold: true });
  doc.moveTo(36, doc.y).lineTo(36 + pageWidth, doc.y).strokeColor('#ccc').stroke();
  doc.moveDown(0.2);

  for (const row of report.rows) {
    drawRow(columns.map((column) => formatValue(row[column.key], column.format)));
  }

  const totals = totalsRow(report);
  if (totals) {
    doc.moveTo(36, doc.y).lineTo(36 + pageWidth, doc.y).strokeColor('#ccc').stroke();
    doc.moveDown(0.2);
    drawRow(totals.map((value, index) => (typeof value === 'number' ? formatValue(value, columns[index].format || 'currency') : value)), { bold: true });
  }

  doc.end();
  return new Promise((resolve) => {
    doc.on('end', () => resolve({ contentType: 'application/pdf', body: Buffer.concat(chunks) }));
  });
}

// Draw a simple bordered table for a {columns, rows} block into an existing PDF document.
function drawTable(doc, columns, rows, totals) {
  const left = doc.page.margins.left;
  const width = doc.page.width - doc.page.margins.left - doc.page.margins.right;
  const colWidth = width / columns.length;
  const line = (cells, bold) => {
    if (doc.y > doc.page.height - 60) doc.addPage();
    const y = doc.y;
    doc.fontSize(bold ? 8.5 : 8).fillColor('#000');
    cells.forEach((cell, index) => {
      const column = columns[index];
      const align = column.format === 'currency' || column.format === 'number' ? 'right' : 'left';
      doc.text(String(cell ?? ''), left + index * colWidth, y, { width: colWidth - 6, align, ellipsis: true });
    });
    doc.moveDown(0.25);
  };
  line(columns.map((column) => column.label), true);
  doc.moveTo(left, doc.y).lineTo(left + width, doc.y).strokeColor('#ccc').stroke();
  doc.moveDown(0.15);
  if (!rows.length) {
    doc.fontSize(8).fillColor('#777').text('None recorded.', left).moveDown(0.2);
    return;
  }
  for (const row of rows) line(columns.map((column) => formatValue(row[column.key], column.format)));
  if (totals && Object.keys(totals).length) {
    doc.moveTo(left, doc.y).lineTo(left + width, doc.y).strokeColor('#ccc').stroke();
    doc.moveDown(0.15);
    line(columns.map((column, index) => {
      if (index === 0) return 'Totals';
      return Object.prototype.hasOwnProperty.call(totals, column.key) ? formatValue(totals[column.key], column.format || 'currency') : '';
    }), true);
  }
}

// Per-asset dossier PDF: identity, per-book financials, each meta section, then photo thumbnails.
function exportDossierPdf(report) {
  const doc = new PDFDocument({ margin: 40, size: 'LETTER' });
  const chunks = [];
  doc.on('data', (chunk) => chunks.push(chunk));
  const meta = report.meta || {};
  const asset = meta.asset || {};

  doc.fontSize(17).fillColor('#000').text(`Asset journal — ${asset.asset_id || ''}`);
  if (asset.description) doc.fontSize(11).fillColor('#333').text(asset.description);
  doc.fontSize(8).fillColor('#777').text(`Generated ${new Date(report.generatedAt || Date.now()).toLocaleString()}`);
  doc.moveDown(0.5);

  // Identity / financial key-values (two columns).
  doc.fontSize(11).fillColor('#000').text('Asset details').moveDown(0.2);
  const entries = Object.entries(asset).filter(([key]) => key !== 'asset_id' && key !== 'description');
  const half = Math.ceil(entries.length / 2);
  const colW = (doc.page.width - doc.page.margins.left - doc.page.margins.right) / 2;
  const startY = doc.y;
  entries.forEach(([key, value], index) => {
    const column = index < half ? 0 : 1;
    const y = startY + (index % half) * 14;
    const label = key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
    doc.fontSize(8).fillColor('#777').text(`${label}: `, doc.page.margins.left + column * colW, y, { continued: true });
    doc.fillColor('#000').text(value === null || value === undefined || value === '' ? '—' : String(value));
  });
  doc.y = startY + half * 14;
  doc.moveDown(0.6);

  doc.fontSize(11).fillColor('#000').text('Depreciation by book').moveDown(0.2);
  drawTable(doc, report.columns || [], report.rows || [], report.totals);
  doc.moveDown(0.4);

  for (const section of meta.sections || []) {
    doc.fontSize(11).fillColor('#000').text(section.title).moveDown(0.2);
    drawTable(doc, section.columns || [], section.rows || []);
    doc.moveDown(0.4);
  }

  const photos = meta.photos || [];
  if (meta.photo_count) {
    doc.fontSize(11).fillColor('#000').text(`Photos (${meta.photo_count})`).moveDown(0.2);
    let x = doc.page.margins.left;
    let rowY = doc.y;
    const thumbW = 160;
    const thumbH = 120;
    for (const photo of photos) {
      if (x + thumbW > doc.page.width - doc.page.margins.right) { x = doc.page.margins.left; rowY += thumbH + 20; }
      if (rowY + thumbH > doc.page.height - 50) { doc.addPage(); rowY = doc.y; x = doc.page.margins.left; }
      try {
        const base64 = String(photo.data || '').replace(/^data:[^;]+;base64,/, '');
        if (base64) doc.image(Buffer.from(base64, 'base64'), x, rowY, { fit: [thumbW, thumbH] });
      } catch {
        doc.fontSize(7).fillColor('#999').text('[image unavailable]', x, rowY + 50, { width: thumbW, align: 'center' });
      }
      doc.fontSize(7).fillColor('#555').text(photo.caption || '', x, rowY + thumbH + 2, { width: thumbW, ellipsis: true });
      x += thumbW + 20;
    }
    doc.y = rowY + thumbH + 18;
  }

  doc.end();
  return new Promise((resolve) => {
    doc.on('end', () => resolve({ contentType: 'application/pdf', body: Buffer.concat(chunks) }));
  });
}

async function exportReport(report, format) {
  if (format === 'csv') return exportCsv(report);
  if (format === 'xlsx') return exportXlsx(report);
  if (format === 'pdf') return report.meta && report.meta.layout === 'dossier' ? exportDossierPdf(report) : exportPdf(report);
  return { contentType: 'application/json', body: JSON.stringify(report, null, 2) };
}

module.exports = { exportReport };
