import * as XLSX from "xlsx";
import { PDFDocument, rgb, StandardFonts } from 'pdf-lib';

/**
 * Export JSON data to CSV
 * @param {Array} data - Array of objects to export
 * @param {string} fileName - File name without extension
 */
export const exportToCSV = (data, fileName = "data") => {
  const headers = Object.keys(data[0] || {});
  const csvContent = [
    headers.join(","), // header row
    ...data.map(row => headers.map(field => `"${row[field] ?? ""}"`).join(",")),
  ].join("\n");

  const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.setAttribute("download", `${fileName}.csv`);
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
};

/**
 * Export JSON data to Excel
 * @param {Array} data - Array of objects to export
 * @param {string} fileName - File name without extension
 */
export const exportToExcel = (data, fileName = "data") => {
  const ws = XLSX.utils.json_to_sheet(data);
  const wb = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
  XLSX.writeFile(wb, `${fileName}.xlsx`);
};

/**
 * Export JSON data to PDF using pdf-lib
 * @param {Array} data - Array of objects to export
 * @param {string} fileName - File name for the PDF (optional)
 */
export const exportToPDF = async (data, fileName = "data") => {
  if (!data || data.length === 0) return;

  // Create a new PDF document
  const pdfDoc = await PDFDocument.create();

  // Set up the font
  const font = await pdfDoc.embedFont(StandardFonts.Helvetica); // Use Helvetica font
  
  // Calculate column widths dynamically based on data content
  const headers = Object.keys(data[0]);
  const rows = data.map(item => headers.map(header => item[header] || ''));

  const getMaxColumnWidth = (columnIndex) => {
    let maxWidth = font.widthOfTextAtSize(headers[columnIndex], 12);
    rows.forEach(row => {
      const cellText = row[columnIndex].toString();
      maxWidth = Math.max(maxWidth, font.widthOfTextAtSize(cellText, 10));
    });
    return maxWidth + 10; // Padding for better spacing
  };

  const columnWidths = headers.map((_, index) => getMaxColumnWidth(index));
  const tableX = 30; // X-coordinate for the table start
  const rowHeight = 20; // Height of each row (can be adjusted)
  const maxPageHeight = 750; // Max available height for content (before a new page is added)
  const pageMargin = 30; // Margin from the top of the page

  let tableY = maxPageHeight; // Start Y position for the table
  const maxPageWidth = 600; // Max available width for content (before a new page is added)

  // Add the headers and rows to the page
  const addHeadersToPage = (page, scaleFactor) => {
    let xPosition = tableX;
    headers.forEach((header, index) => {
      page.drawText(header, {
        x: xPosition,
        y: tableY,
        font,
        size: 12 * scaleFactor, // Scale the header font size
        color: rgb(0, 0, 0),
      });
      xPosition += columnWidths[index] * scaleFactor; // Adjust X position based on scaling
    });
    tableY -= rowHeight; // Move down after adding headers
  };

  // Add a new page and reset the table position
  const addNewPage = (scaleFactor) => {
    const page = pdfDoc.addPage([600, 800]);
    tableY = maxPageHeight; // Reset Y position for the new page
    addHeadersToPage(page, scaleFactor); // Re-add headers to the new page
    return page;
  };

  // Create the first page and add headers
  let page = pdfDoc.addPage([600, 800]);

  // Check if the content fits within the page width, scale if necessary
  const checkPageWidth = (row) => {
    let totalWidth = columnWidths.reduce((acc, width) => acc + width, 0);
    let scaleFactor = 1;
    if (totalWidth > maxPageWidth) {
      scaleFactor = maxPageWidth / totalWidth; // Scale down if necessary
    }

    return scaleFactor;
  };

  // Function to check for page breaks when adding a new row
  const checkPageBreak = () => {
    if (tableY - rowHeight < pageMargin) {
      page = addNewPage(scaleFactor); // Add a new page if there is no space for the next row
    }
  };

  // Add rows to the PDF with pagination and horizontal scaling
  rows.forEach(row => {
    checkPageBreak(); // Check for page break before adding each row

    const scaleFactor = checkPageWidth(row); // Get the scaling factor for the row

    // Add headers to the first page and each new page with the same scale factor
    if (tableY === maxPageHeight) {
      addHeadersToPage(page, scaleFactor); // Add headers only on the first page
    }

    let xPosition = tableX;
    row.forEach((value, index) => {
      page.drawText(value.toString(), {
        x: xPosition,
        y: tableY,
        font,
        size: 10 * scaleFactor, // Scale the font size
        color: rgb(0, 0, 0),
      });
      xPosition += columnWidths[index] * scaleFactor; // Adjust X position based on scaling
    });

    tableY -= rowHeight; // Move down to the next row position
  });

  // Serialize the document to bytes
  const pdfBytes = await pdfDoc.save();

  // Trigger a download of the PDF
  const blob = new Blob([pdfBytes], { type: 'application/pdf' });
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = `${fileName}.pdf`;
  link.click();
};

/**
 * Print the HTML table by accepting the table element or a reference.
 * @param {HTMLElement} table - The table element (or ref) to print
 */
export const printTable = (table) => {
  if (table) {
    const newWindow = window.open("", "", "width=600,height=600"); // Open a new window

    // Inject styles for the table and body
    newWindow.document.write("<html><head><title>Print Table</title>");
    const style = document.createElement('style');
    style.innerHTML = `
      body { font-family: Arial, sans-serif; }
      table { border-collapse: collapse; width: 100%; }
      th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
      th { background-color: #f2f2f2; }
    `;
    newWindow.document.head.appendChild(style);
    
    newWindow.document.write("</head><body>");
    newWindow.document.write(table.outerHTML); // Write the table HTML to the new window
    newWindow.document.write("</body></html>");
    
    newWindow.document.close(); // Close the document stream
    
    // Wait for the document to load before triggering print
    newWindow.onload = () => {
      newWindow.print(); // Trigger the print dialog after the content is loaded
    };
  }
};
