import PDFDocument from "pdfkit";
import type { Response } from "express";
import { PdfHeader } from "./components/PdfHeader.js";

const COLORS = {
    primary: "#0F5132",
    accent: "#198754",
    text: "#212529",
    muted: "#6C757D",
    border: "#DEE2E6",
    rowAlt: "#F8F9FA",
    white: "#FFFFFF",
    orange: "#D97706",
};

const PAGE_MARGIN = 40;

function fmt(value: number | string | undefined | null): string {
    const n = Number(value ?? 0);
    return isNaN(n) ? "-" : n.toLocaleString("en-IN", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}

export class StockReportPdf {
    static async generate(
        records: any[],
        res: Response,
        filters?: {
            search?: string;
            dateFrom?: string;
            dateTo?: string;
        }
    ) {
        const doc = new PDFDocument({
            size: "A4",
            layout: "landscape",
            margin: PAGE_MARGIN,
            bufferPages: true,
        });

        res.setHeader("Content-Type", "application/pdf");
        res.setHeader(
            "Content-Disposition",
            `attachment; filename="stock-report-${Date.now()}.pdf"`
        );
        res.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        doc.pipe(res);

        const pageWidth = doc.page.width - PAGE_MARGIN * 2;

        await PdfHeader.draw(doc, pageWidth, PAGE_MARGIN, "FINAL STOCK REPORT");

        this.drawFilterLine(doc, pageWidth, filters);
        this.drawTable(doc, records, pageWidth);
        this.drawTotals(doc, records, pageWidth);
        this.drawFooter(doc, pageWidth);

        doc.end();
    }

    private static drawFilterLine(
        doc: PDFKit.PDFDocument,
        pageWidth: number,
        filters?: { search?: string; dateFrom?: string; dateTo?: string }
    ) {
        const parts: string[] = [];
        if (filters?.dateFrom)
            parts.push(`From: ${new Date(filters.dateFrom).toLocaleDateString("en-GB").replace(/\//g, "-")}`);
        if (filters?.dateTo)
            parts.push(`To: ${new Date(filters.dateTo).toLocaleDateString("en-GB").replace(/\//g, "-")}`);
        if (filters?.search) parts.push(`Search: "${filters.search}"`);

        if (parts.length) {
            doc
                .font("Helvetica")
                .fontSize(8.5)
                .fillColor(COLORS.muted)
                .text(parts.join("   |   "), PAGE_MARGIN, doc.y, {
                    width: pageWidth,
                    align: "right",
                });
            doc.y += 4;
        }
        doc.y += 10;
    }

    private static drawTable(doc: PDFKit.PDFDocument, records: any[], pageWidth: number) {
        const pw = pageWidth;

        // Column layout — landscape A4 usable ≈ 762 pts
        const cols = {
            no:           { x: PAGE_MARGIN + pw * 0.000, width: pw * 0.028 },
            date:         { x: PAGE_MARGIN + pw * 0.028, width: pw * 0.075 },
            lotNo:        { x: PAGE_MARGIN + pw * 0.103, width: pw * 0.065 },
            supplier:     { x: PAGE_MARGIN + pw * 0.168, width: pw * 0.115 },
            vegetable:    { x: PAGE_MARGIN + pw * 0.283, width: pw * 0.085 },
            purchased:    { x: PAGE_MARGIN + pw * 0.368, width: pw * 0.068 },
            bags:         { x: PAGE_MARGIN + pw * 0.436, width: pw * 0.045 },
            wsSales:      { x: PAGE_MARGIN + pw * 0.481, width: pw * 0.068 },
            wsSpoilage:   { x: PAGE_MARGIN + pw * 0.549, width: pw * 0.068 },
            retAlloc:     { x: PAGE_MARGIN + pw * 0.617, width: pw * 0.068 },
            retSales:     { x: PAGE_MARGIN + pw * 0.685, width: pw * 0.068 },
            retSpoilage:  { x: PAGE_MARGIN + pw * 0.753, width: pw * 0.060 },
            retRem:       { x: PAGE_MARGIN + pw * 0.813, width: pw * 0.060 },
            wsRem:        { x: PAGE_MARGIN + pw * 0.873, width: pw * 0.072 },
            balance:      { x: PAGE_MARGIN + pw * 0.945, width: pw * 0.055 },
        };

        const rowHeight = 22;
        const headerH   = 26;

        const drawTableHeader = () => {
            const y = doc.y;
            doc
                .font("Helvetica-Bold")
                .fontSize(6.8)
                .fillColor(COLORS.primary)
                .text("#",           cols.no.x,          y + 6, { width: cols.no.width,         align: "center" })
                .text("DATE",        cols.date.x,         y + 6, { width: cols.date.width })
                .text("LOT NO",      cols.lotNo.x,        y + 6, { width: cols.lotNo.width })
                .text("SUPPLIER",    cols.supplier.x,     y + 6, { width: cols.supplier.width })
                .text("VEGETABLE",   cols.vegetable.x,    y + 6, { width: cols.vegetable.width })
                .text("PURCH (KG)",  cols.purchased.x,    y + 6, { width: cols.purchased.width,  align: "right" })
                .text("BAGS",        cols.bags.x,         y + 6, { width: cols.bags.width,       align: "right" })
                .text("WS SOLD",     cols.wsSales.x,      y + 6, { width: cols.wsSales.width,    align: "right" })
                .text("WS SPOIL",    cols.wsSpoilage.x,   y + 6, { width: cols.wsSpoilage.width, align: "right" })
                .text("RET ALLOC",   cols.retAlloc.x,     y + 6, { width: cols.retAlloc.width,   align: "right" })
                .text("RET SOLD",    cols.retSales.x,     y + 6, { width: cols.retSales.width,   align: "right" })
                .text("RET SPOIL",   cols.retSpoilage.x,  y + 6, { width: cols.retSpoilage.width,align: "right" })
                .text("RET REM",     cols.retRem.x,       y + 6, { width: cols.retRem.width,     align: "right" })
                .text("WS REM",      cols.wsRem.x,        y + 6, { width: cols.wsRem.width,      align: "right" })
                .text("BALANCE",     cols.balance.x,      y + 6, { width: cols.balance.width - 2,align: "right" });

            doc.y = y + headerH;

            doc
                .moveTo(PAGE_MARGIN, doc.y)
                .lineTo(PAGE_MARGIN + pw, doc.y)
                .strokeColor(COLORS.primary)
                .lineWidth(1)
                .stroke();

            doc.y += 3;
        };

        const ensureSpace = (needed: number) => {
            if (doc.y + needed > doc.page.height - PAGE_MARGIN - 60) {
                doc.addPage();
                doc.y = PAGE_MARGIN;
                drawTableHeader();
            }
        };

        drawTableHeader();

        records.forEach((r, i) => {
            ensureSpace(rowHeight);
            const y = doc.y;

            if (i % 2 === 1) {
                doc.rect(PAGE_MARGIN, y, pw, rowHeight).fill(COLORS.rowAlt);
            }

            const dateStr = r.purchaseDate
                ? new Date(r.purchaseDate).toLocaleDateString("en-GB").replace(/\//g, "-")
                : "-";

            // Row number
            doc
                .font("Helvetica-Bold")
                .fontSize(7)
                .fillColor(COLORS.accent)
                .text(`${i + 1}`, cols.no.x, y + 5, { width: cols.no.width, align: "center" });

            // Text columns
            doc.font("Helvetica").fontSize(7.5).fillColor(COLORS.text);
            doc.text(dateStr,                                                              cols.date.x,      y + 5, { width: cols.date.width - 2,     lineBreak: false });
            doc.text(r.lotNo ?? "-",                                                       cols.lotNo.x,     y + 5, { width: cols.lotNo.width - 2,    ellipsis: true, lineBreak: false });
            doc.text(r.supplier?.name ?? r.cashSupplierName ?? r.supplierName ?? "-",     cols.supplier.x,  y + 5, { width: cols.supplier.width - 2, ellipsis: true, lineBreak: false });
            doc.text(r.vegetable?.name ?? "-",                                             cols.vegetable.x, y + 5, { width: cols.vegetable.width - 2,ellipsis: true, lineBreak: false });

            // Numeric columns
            doc.font("Helvetica").fontSize(7.5).fillColor(COLORS.text);
            doc.text(fmt(r.quantity),            cols.purchased.x,   y + 5, { width: cols.purchased.width - 2,   align: "right", lineBreak: false });
            doc.text(fmt(r.bags),                cols.bags.x,        y + 5, { width: cols.bags.width - 2,        align: "right", lineBreak: false });
            doc.text(fmt(r.wholesaleSalesQty),   cols.wsSales.x,     y + 5, { width: cols.wsSales.width - 2,     align: "right", lineBreak: false });
            doc.text(fmt(r.wholesaleSpoilageQty),cols.wsSpoilage.x,  y + 5, { width: cols.wsSpoilage.width - 2,  align: "right", lineBreak: false });
            doc.text(fmt(r.retailAllocatedQty),  cols.retAlloc.x,    y + 5, { width: cols.retAlloc.width - 2,    align: "right", lineBreak: false });
            doc.text(fmt(r.retailSalesQty),      cols.retSales.x,    y + 5, { width: cols.retSales.width - 2,    align: "right", lineBreak: false });
            doc.text(fmt(r.retailSpoilageQty),   cols.retSpoilage.x, y + 5, { width: cols.retSpoilage.width - 2, align: "right", lineBreak: false });
            doc.text(fmt(r.retailRemainingQty),  cols.retRem.x,      y + 5, { width: cols.retRem.width - 2,      align: "right", lineBreak: false });

            doc.font("Helvetica-Bold").fontSize(7.5).fillColor(COLORS.primary);
            doc.text(fmt(r.remainingQuantity),   cols.wsRem.x,       y + 5, { width: cols.wsRem.width - 2,       align: "right", lineBreak: false });

            // Balance = wsRem + retailRemaining
            const balance = Number(r.remainingQuantity ?? 0) + Number(r.retailRemainingQty ?? 0);
            doc.font("Helvetica-Bold").fontSize(7.5).fillColor(COLORS.orange);
            doc.text(fmt(balance),               cols.balance.x,     y + 5, { width: cols.balance.width - 4,     align: "right", lineBreak: false });

            doc.y = y + rowHeight;
        });

        doc
            .moveTo(PAGE_MARGIN, doc.y)
            .lineTo(PAGE_MARGIN + pw, doc.y)
            .strokeColor(COLORS.border)
            .lineWidth(0.5)
            .stroke();

        doc.y += 12;
    }

    private static drawTotals(doc: PDFKit.PDFDocument, records: any[], pageWidth: number) {
        const sum = (key: string) => records.reduce((s, r) => s + Number(r[key] ?? 0), 0);

        const totalPurchased   = sum("quantity");
        const totalWsSales     = sum("wholesaleSalesQty");
        const totalWsSpoilage  = sum("wholesaleSpoilageQty");
        const totalRetAlloc    = sum("retailAllocatedQty");
        const totalRetSales    = sum("retailSalesQty");
        const totalRetSpoilage = sum("retailSpoilageQty");
        const totalRetRem      = sum("retailRemainingQty");
        const totalWsRem       = sum("remainingQuantity");
        const totalBalance     = totalWsRem + totalRetRem;

        const boxWidth = pageWidth * 0.46;
        const labelX   = PAGE_MARGIN + pageWidth - boxWidth;
        const valX     = labelX + boxWidth * 0.60;
        const valWidth = boxWidth * 0.40;
        const y0       = doc.y;

        doc
            .moveTo(labelX, y0)
            .lineTo(PAGE_MARGIN + pageWidth, y0)
            .strokeColor(COLORS.primary)
            .lineWidth(0.75)
            .stroke();

        doc.y = y0 + 6;

        const drawRow = (label: string, value: string, bold = false, color = COLORS.text) => {
            const font = bold ? "Helvetica-Bold" : "Helvetica";
            const size = bold ? 9.5 : 8.5;
            doc.font(font).fontSize(size).fillColor(COLORS.text).text(label, labelX, doc.y, { width: boxWidth * 0.60 });
            doc.font("Helvetica-Bold").fontSize(size).fillColor(color)
               .text(value, valX, doc.y - (size + 2), { width: valWidth, align: "right" });
            doc.y += 3;
        };

        drawRow("Total Purchased (KG):",    fmt(totalPurchased));
        drawRow("Total WS Sold:",            fmt(totalWsSales));
        drawRow("Total WS Spoilage:",        fmt(totalWsSpoilage));
        drawRow("Total Retail Allocated:",   fmt(totalRetAlloc));
        drawRow("Total Retail Sold:",        fmt(totalRetSales));
        drawRow("Total Retail Spoilage:",    fmt(totalRetSpoilage));
        drawRow("Total Retail Remaining:",   fmt(totalRetRem));
        drawRow("Total WS Remaining:",       fmt(totalWsRem));
        drawRow("Total Balance Stock (KG):", fmt(totalBalance), true, COLORS.orange);

        doc.y += 12;
    }

    private static drawFooter(doc: PDFKit.PDFDocument, pageWidth: number) {
        const y = doc.page.height - PAGE_MARGIN - 20;
        doc
            .font("Helvetica-Oblique")
            .fontSize(8.5)
            .fillColor(COLORS.muted)
            .text(
                "This is a computer-generated stock report.",
                PAGE_MARGIN,
                y,
                { width: pageWidth, align: "center" }
            );
    }
}
