import jsPDF from "jspdf";
import "jspdf-autotable"; // registers autoTable with jsPDF
import { SHOP_INFO } from "./constants";
import { loadBengaliFont, renderBengaliText, containsBengali } from "./pdfFonts";
export const GeneratePDFView = async (
    data,
    columns,
    operation_info = false,
    reportTitle = "",
    startDate = false,
    endDate = false,
    grossDiscount = 0
) => {
    const doc = new jsPDF("landscape", "mm", "a4");

    // Load Bengali fonts
    try {
        await loadBengaliFont(doc);
    } catch (error) {
        console.error("Failed to load Bengali fonts:", error);
    }
    const pageWidth = doc.internal.pageSize.getWidth();

    // Company Info Header - Balanced spacing
    doc.setFontSize(16);
    doc.setFont("Helvetica", "bold");

    let currentY = 11; // Start from top with balanced margin

    // Check if company name contains Bengali text
    if (containsBengali(SHOP_INFO.name)) {
        renderBengaliText(doc, SHOP_INFO.name, pageWidth / 2, currentY, { align: "center" });
    } else {
        doc.text(SHOP_INFO.name, pageWidth / 2, currentY, { align: "center" });
    }

    currentY += 6; // Balanced spacing after company name

    doc.setFontSize(10);
    doc.setFont("Helvetica", "normal");

    // Handle address with proper line wrapping and balanced spacing
    const addressText = SHOP_INFO.address || "";
    const maxAddressWidth = pageWidth - 20; // Leave margins
    
    // Split address into multiple lines if needed
    let addressLines = [];
    if (containsBengali(addressText)) {
        addressLines = doc.splitTextToSize(addressText, maxAddressWidth);
    } else {
        addressLines = doc.splitTextToSize(addressText, maxAddressWidth);
    }

    // Render each address line with balanced spacing
    addressLines.forEach((line, index) => {
        if (containsBengali(line)) {
            renderBengaliText(doc, line, pageWidth / 2, currentY + (index * 3.5), { align: "center" });
        } else {
            doc.text(line, pageWidth / 2, currentY + (index * 3.5), { align: "center" });
        }
    });

    // Update currentY based on number of address lines with balanced spacing
    currentY += (addressLines.length * 3.5) + 3; // 3.5mm per line + 3mm spacing

    const contactInfo = `Phone: ${SHOP_INFO.phone} | Email: ${SHOP_INFO.email}`;
    if (containsBengali(contactInfo)) {
        renderBengaliText(doc, contactInfo, pageWidth / 2, currentY, { align: "center" });
    } else {
        doc.text(contactInfo, pageWidth / 2, currentY, { align: "center" });
    }

    currentY += 6; // Balanced spacing before report title

    // Report Title
    doc.setFontSize(14);
    doc.setFont("Helvetica", "bold");
    const title = reportTitle || "Report";

    if (containsBengali(title)) {
        renderBengaliText(doc, title, pageWidth / 2, currentY, { align: "center" });
    } else {
        doc.text(title, pageWidth / 2, currentY, { align: "center" });
    }

    currentY += 5; // Balanced spacing after title

    // Date Range
    const formatDate = (date) =>
        new Intl.DateTimeFormat("en-GB", {
            day: "2-digit",
            month: "short",
            year: "numeric",
        })
            .format(new Date(date))
            .replace(/ /g, "-");

    const dateText =
        startDate && endDate
            ? `Period: ${formatDate(startDate)} to ${formatDate(endDate)}`
            : `Period: ${formatDate(new Date())}`;

    doc.setFontSize(10);
    doc.setFont("Helvetica", "normal");

    if (containsBengali(dateText)) {
        renderBengaliText(doc, dateText, pageWidth / 2, currentY, { align: "center" });
    } else {
        doc.text(dateText, pageWidth / 2, currentY, { align: "center" });
    }

    currentY += 5; // Balanced spacing after date

    if (operation_info) {
        // Show supplier information in a single compact line
        const operationInfoText = `Report for : ${operation_info.name} `;
        doc.setFontSize(11);
        doc.setFont("Helvetica", "normal");

        // Split long text if it exceeds page width
        const maxWidth = pageWidth - 30; // Leave margins
        const textLines = doc.splitTextToSize(operationInfoText, maxWidth);

        if (containsBengali(operationInfoText)) {
            textLines.forEach((line, index) => {
                renderBengaliText(doc, line, pageWidth / 2, currentY + (index * 3.5), { align: "center" });
            });
        } else {
            textLines.forEach((line, index) => {
                doc.text(line, pageWidth / 2, currentY + (index * 3.5), { align: "center" });
            });
        }

        // Update currentY for table start position with balanced spacing
        currentY += (textLines.length * 3.5) + 3; // Balanced spacing after operation info
    }

    // Prepare Table Data
    const visibleColumns = columns.filter((col) => col.visible);
    const exportColumns = visibleColumns.map((col) => ({
        header: col.label,
        dataKey: col.key,
    }));

    const tableData = data.map((row, rowIndex) => {
        const rowData = {};
        visibleColumns.forEach((col) => {
            const cellValue = col.body
                ? col.body(row, rowIndex, data)
                : row[col.key];

            // Store the actual value for jsPDF AutoTable to use
            rowData[col.key] = cellValue;

            // Check if any cell contains Bengali text for future reference
            if (typeof cellValue === 'string' && containsBengali(cellValue)) {
                rowData._hasBengali = true;
                rowData[`_bengali_${col.key}`] = true;
            }
        });
        return rowData;
    });

    // Total Footer Calculation
    const footerData = {};
    visibleColumns.forEach((col) => {
        if (typeof col.footer === "function") {
            footerData[col.key] = col.footer(data);
        } else {
            footerData[col.key] = col.footer || "";
        }
    });
    const footerLabel = {};
    visibleColumns.forEach((col) => {
        footerLabel[col.key] = col.footerLabel || "";
    });

    const headStyles = {
        fillColor: [69, 69, 69],
        textColor: 255,
        fontStyle: "bold",
        halign: "center",
    };

    const bodyStyles = {
        lineWidth: 0.1,
        lineColor: [69, 69, 69],
    };

    // Calculate column widths based on width property from column config
    const calculateColumnWidths = () => {
        const availableWidth = pageWidth - 20; // Leave margins (10mm each side)
        const columnWidths = {};

        // Check if any column has width property
        const hasWidthProperty = visibleColumns.some(col => col.width);
        
        if (hasWidthProperty) {
            // Use width property from column config
            const percentageWidths = {};
            const fixedWidths = {};
            let totalPercentage = 0;

            // First pass: collect all width definitions from visible columns only
            visibleColumns.forEach((col) => {
                if (col.width) {
                    const widthStr = String(col.width).trim();
                    if (widthStr.endsWith('%')) {
                        // Percentage width
                        const percentage = parseFloat(widthStr);
                        if (!isNaN(percentage) && percentage > 0) {
                            percentageWidths[col.key] = percentage;
                            totalPercentage += percentage;
                        }
                    } else {
                        // Fixed width (in mm) - remove 'mm' if present
                        const fixed = parseFloat(widthStr.replace('mm', '').trim());
                        if (!isNaN(fixed) && fixed > 0) {
                            fixedWidths[col.key] = fixed;
                        }
                    }
                }
            });

            // Calculate total fixed width
            const totalFixedWidth = Object.values(fixedWidths).reduce((sum, w) => sum + w, 0);
            const widthForPercentages = availableWidth - totalFixedWidth;

            // Second pass: assign widths based on percentages
            visibleColumns.forEach((col) => {
                if (fixedWidths[col.key]) {
                    // Fixed width column
                    columnWidths[col.key] = fixedWidths[col.key];
                } else if (percentageWidths[col.key]) {
                    // Percentage width column - use percentage of available width
                    // If total percentage != 100%, scale proportionally
                    const scaleFactor = totalPercentage > 0 && totalPercentage !== 100 
                        ? (100 / totalPercentage) 
                        : 1;
                    const adjustedPercentage = percentageWidths[col.key] * scaleFactor;
                    columnWidths[col.key] = (adjustedPercentage / 100) * widthForPercentages;
                } else {
                    // Column without width - will distribute remaining space
                    columnWidths[col.key] = null;
                }
            });

            // Calculate remaining width for columns without width definition
            const usedWidth = Object.values(columnWidths).reduce((sum, w) => sum + (w || 0), 0);
            const remainingForUndefined = Math.max(0, availableWidth - usedWidth);
            const colsWithoutWidth = visibleColumns.filter(c => !c.width && !fixedWidths[c.key]).length;

            // Distribute remaining width to columns without width definition
            if (colsWithoutWidth > 0 && remainingForUndefined > 0) {
                visibleColumns.forEach((col) => {
                    if (!col.width && !fixedWidths[col.key] && columnWidths[col.key] === null) {
                        columnWidths[col.key] = remainingForUndefined / colsWithoutWidth;
                    }
                });
            } else if (colsWithoutWidth > 0) {
                // If no remaining width, give minimum width
                visibleColumns.forEach((col) => {
                    if (!col.width && !fixedWidths[col.key] && columnWidths[col.key] === null) {
                        columnWidths[col.key] = 15; // Minimum width
                    }
                });
            }

            // Final normalization to ensure total equals availableWidth exactly
            const totalAssigned = Object.values(columnWidths).reduce((sum, w) => sum + (w || 0), 0);
            if (Math.abs(totalAssigned - availableWidth) > 0.01 && totalAssigned > 0) {
                const finalScaleFactor = availableWidth / totalAssigned;
                visibleColumns.forEach((col) => {
                    if (columnWidths[col.key] !== null && columnWidths[col.key] > 0) {
                        columnWidths[col.key] = columnWidths[col.key] * finalScaleFactor;
                    }
                });
            }
        } else {
            // Fallback: content-based calculation if no width property
            const contentLengths = {};

            visibleColumns.forEach((col) => {
                let maxLength = col.label ? col.label.length : 0;
                
                tableData.forEach((row) => {
                    const cellValue = row[col.key];
                    if (cellValue !== null && cellValue !== undefined) {
                        const valueStr = String(cellValue);
                        const estimatedLength = typeof cellValue === 'number' 
                            ? valueStr.length * 1.2
                            : valueStr.length > 50 
                                ? 50
                                : valueStr.length;
                        if (estimatedLength > maxLength) {
                            maxLength = estimatedLength;
                        }
                    }
                });

                contentLengths[col.key] = maxLength;
            });

            const totalLength = Object.values(contentLengths).reduce((sum, len) => sum + Math.max(len, 1), 0);

            visibleColumns.forEach((col) => {
                const contentLength = Math.max(contentLengths[col.key] || 1, 1);
                const proportionalWidth = (contentLength / totalLength) * availableWidth;
                columnWidths[col.key] = Math.max(Math.min(proportionalWidth, availableWidth * 0.4), 15);
            });

            // Normalize to fill full width
            const totalAssigned = Object.values(columnWidths).reduce((sum, w) => sum + w, 0);
            if (totalAssigned !== availableWidth && totalAssigned > 0) {
                const scaleFactor = availableWidth / totalAssigned;
                visibleColumns.forEach((col) => {
                    columnWidths[col.key] = columnWidths[col.key] * scaleFactor;
                });
            }
        }

        return columnWidths;
    };

    const columnWidths = calculateColumnWidths();

    // autoTable uses column index (0, 1, 2...) not key for columnStyles
    const columnStyles = {};
    visibleColumns.forEach((col, index) => {
        const width = columnWidths[col.key];
        // Get alignment from bodyStyle.textAlign or col.align
        const alignment = col.bodyStyle?.textAlign || col.align || "left";
        // Convert CSS textAlign to autoTable halign
        const halign = alignment === "right" ? "right" : alignment === "center" ? "center" : "left";
        
        columnStyles[index] = { 
            halign: halign,
            cellWidth: width || 'auto',
            overflow: 'linebreak',
            cellPadding: { top: 2, bottom: 2, left: 2, right: 2 },
            minCellHeight: 5,
            maxCellHeight: 60 // Increased to allow more text wrapping
        };
    });

    // Calculate dynamic startY position with balanced spacing
    const tableStartY = currentY + 4; // Balanced spacing before table

    // Generate Table
    doc.autoTable({
        head: [exportColumns.map((col) => col.header)],
        body: tableData.map((row) =>
            exportColumns.map((col) => {
                const cellValue = row[col.dataKey];
                // Convert to string and handle null/undefined
                if (cellValue === null || cellValue === undefined) {
                    return '';
                }
                return String(cellValue);
            })
        ),
        theme: "grid",
        headStyles,
        bodyStyles,
        columnStyles,
        startY: tableStartY,
        styles: {
            cellPadding: { top: 2, bottom: 2, left: 2, right: 2 },
            overflow: 'linebreak',
            fontSize: 8,
            minCellHeight: 5,
            maxCellHeight: 60 // Increased to allow more text wrapping
        },
        headStyles: {
            ...headStyles,
            fontSize: 9,
            cellPadding: { top: 3, bottom: 3, left: 2, right: 2 }
        },
        margin: { left: 10, right: 10 },
        tableWidth: pageWidth - 20, // Full width minus margins
        showHead: 'everyPage',
        // Handle page footer
        didDrawPage: () => {
            doc.setFontSize(9);
            doc.setTextColor(100);
            const y = doc.internal.pageSize.getHeight();

            // doc.text(
            //     "For questions, contact us at info@company.com",
            //     pageWidth / 2,
            //     y - 15,
            //     { align: "center" }
            // );
            const footerText = "Powered by DATADSS LTD";
            if (containsBengali(footerText)) {
                renderBengaliText(doc, footerText, pageWidth / 2, y - 10, { align: "center" });
            } else {
                doc.text(footerText, pageWidth / 2, y - 10, { align: "center" });
            }
        },
        // Handle Bengali text in table cells
        didDrawCell: (data) => {
            // Check if we need to process cell for Bengali text rendering
            if (data.section === 'body' &&
                tableData[data.row.index] &&
                tableData[data.row.index][`_bengali_${visibleColumns[data.column.index]?.key}`]) {

                const cellValue = tableData[data.row.index][visibleColumns[data.column.index]?.key];
                const cell = data.cell;

                // Clear the default rendered text
                doc.setFillColor(255, 255, 255);
                doc.rect(cell.x, cell.y, cell.width, cell.height, 'F');

                // Draw border again since we cleared it
                doc.setDrawColor(69, 69, 69);
                doc.setLineWidth(0.1);
                doc.rect(cell.x, cell.y, cell.width, cell.height, 'S');

                // Render Bengali text properly
                const align = visibleColumns[data.column.index]?.align || 'left';
                let x = cell.x + (align === 'center' ? cell.width / 2 :
                    align === 'right' ? cell.width - 2 : 2);

                renderBengaliText(doc, cellValue, x, cell.y + cell.height / 2 + 1, {
                    align: align,
                    baseline: 'middle'
                });
            }

            // Process last row for footer
            const isLastRow = data.row.index === data.table.body.length - 1;
            if (!isLastRow) return;

            const colKey = visibleColumns?.[data.column.index]?.key;
            if (!colKey) return;

            const footerValue = footerData?.[colKey];
            const rawFooterLabel = footerLabel?.[colKey];
            const footerLabelText = rawFooterLabel ?? colKey;

            if (
                footerValue === "" ||
                footerValue === null ||
                footerValue === undefined
            )
                return;

            // Config
            const font = "Helvetica";
            const baseFontSize = 8;
            const paddingTop = 6;

            const discountAmount = Number(grossDiscount ?? 0);
            const isNumeric = typeof footerValue === "number" || !isNaN(footerValue);
            const cleanFooterLabel = String(footerLabelText ?? "").trim();

            const isTotalColumn =
                cleanFooterLabel.toLowerCase() === "total" ||
                colKey.trim().toLowerCase() === "total";

            const value = isNumeric ? Number(footerValue) : footerValue;
            const totalValue = isTotalColumn && isNumeric
                ? value - discountAmount
                : value;

            const lines = [];

            if (isTotalColumn && discountAmount > 0) {
                lines.push({
                    text: `Gross Dis: ${discountAmount.toFixed(2)}`,
                    size: baseFontSize,
                    weight: "normal",
                });
            }

            const footerValueText = isNumeric
                ? Number(totalValue).toFixed(2)
                : String(totalValue ?? "");
            const footerMainText = cleanFooterLabel
                ? `${cleanFooterLabel}: ${footerValueText}`
                : footerValueText;

            lines.push({
                text: footerMainText,
                size: baseFontSize,
                weight: "normal",
            });

            // Render inside column bounds so long labels (e.g. "Total (unit value): …")
            // do not extend into neighbouring columns and overlap other footers.
            const pageHeight = doc.internal.pageSize.getHeight();
            const bottomMargin = 15;
            const cellPad = 2;
            const maxTextWidth = Math.max(data.cell.width - cellPad * 2, 8);
            const rightX = data.cell.x + data.cell.width - cellPad;
            const wrappedLineHeight = 4.1;

            let totalWrappedLines = 0;
            lines.forEach((line) => {
                doc.setFont(font, line.weight);
                doc.setFontSize(line.size);
                const wrapped = doc.splitTextToSize(
                    String(line.text),
                    maxTextWidth
                );
                totalWrappedLines += wrapped.length;
            });

            const requiredHeight = totalWrappedLines * wrappedLineHeight;
            let yBase = data.cell.y + data.cell.height + paddingTop;
            if (yBase + requiredHeight > pageHeight - bottomMargin) {
                yBase = Math.max(
                    data.cell.y + 2,
                    pageHeight - bottomMargin - requiredHeight
                );
            }

            let yCursor = yBase;
            lines.forEach((line) => {
                doc.setFont(font, line.weight);
                doc.setFontSize(line.size);
                const wrapped = doc.splitTextToSize(
                    String(line.text),
                    maxTextWidth
                );
                wrapped.forEach((ln) => {
                    if (yCursor + wrappedLineHeight > pageHeight - bottomMargin) {
                        return;
                    }
                    doc.text(ln, rightX, yCursor, { align: "right" });
                    yCursor += wrappedLineHeight;
                });
            });
        }

    });

    return doc; // return the jsPDF instance
};
