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",
};

const PAGE_MARGIN = 35;

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 LotWiseSalesPdf {
    static async generate(
        records: any[],
        res: Response,
        filters?: { date?: string | undefined; lotNo?: string | undefined; vegetable?: string | undefined; search?: string | undefined }
    ) {
        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="lot-wise-sales-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, "LOT-WISE SALES 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?: { date?: string | undefined; lotNo?: string | undefined; vegetable?: string | undefined; search?: string | undefined }
    ) {
        const parts: string[] = [];
        if (filters?.date) {
            try {
                parts.push(`Date: ${new Date(filters.date).toLocaleDateString("en-GB").replace(/\//g, "-")}`);
            } catch {
                parts.push(`Date: ${filters.date}`);
            }
        }
        if (filters?.lotNo) parts.push(`LOT No: ${filters.lotNo}`);
        if (filters?.vegetable) parts.push(`Vegetable: ${filters.vegetable}`);
        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 += 8;
    }

    private static drawTable(
        doc: PDFKit.PDFDocument,
        records: any[],
        pageWidth: number
    ) {
        const pw = pageWidth;
        const cols = {
            no:        { x: PAGE_MARGIN,                 width: pw * 0.04 },
            lotNo:     { x: PAGE_MARGIN + pw * 0.04,     width: pw * 0.11 },
            vegetable: { x: PAGE_MARGIN + pw * 0.15,     width: pw * 0.13 },
            invoiceNo: { x: PAGE_MARGIN + pw * 0.28,     width: pw * 0.11 },
            date:      { x: PAGE_MARGIN + pw * 0.39,     width: pw * 0.09 },
            customer:  { x: PAGE_MARGIN + pw * 0.48,     width: pw * 0.15 },
            qty:       { x: PAGE_MARGIN + pw * 0.63,     width: pw * 0.08 },
            bags:      { x: PAGE_MARGIN + pw * 0.71,     width: pw * 0.06 },
            rate:      { x: PAGE_MARGIN + pw * 0.77,     width: pw * 0.07 },
            total:     { x: PAGE_MARGIN + pw * 0.84,     width: pw * 0.09 },
            supplier:  { x: PAGE_MARGIN + pw * 0.93,     width: pw * 0.07 },
        };

        const rowHeight = 20;
        const headerH = 22;

        const drawTableHeader = () => {
            const y = doc.y;
            doc
                .font("Helvetica-Bold")
                .fontSize(7.5)
                .fillColor(COLORS.primary)
                .text("#",          cols.no.x,        y + 5, { width: cols.no.width,        align: "center" })
                .text("LOT NO",     cols.lotNo.x,     y + 5, { width: cols.lotNo.width })
                .text("VEGETABLE",  cols.vegetable.x, y + 5, { width: cols.vegetable.width })
                .text("INVOICE NO", cols.invoiceNo.x, y + 5, { width: cols.invoiceNo.width })
                .text("DATE",       cols.date.x,      y + 5, { width: cols.date.width })
                .text("CUSTOMER",   cols.customer.x,  y + 5, { width: cols.customer.width })
                .text("QTY (KG)",   cols.qty.x,       y + 5, { width: cols.qty.width,       align: "right" })
                .text("BAGS",       cols.bags.x,      y + 5, { width: cols.bags.width,      align: "right" })
                .text("RATE/KG",    cols.rate.x,      y + 5, { width: cols.rate.width,      align: "right" })
                .text("TOTAL (INR)",cols.total.x,     y + 5, { width: cols.total.width,     align: "right" })
                .text("SUPPLIER",   cols.supplier.x,  y + 5, { width: cols.supplier.width,  align: "left" });

            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) => {
            const bottomLimit = doc.page.height - PAGE_MARGIN - 60;
            if (doc.y + needed > bottomLimit) {
                doc.addPage();
                doc.y = PAGE_MARGIN;
                drawTableHeader();
            }
        };

        drawTableHeader();

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

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

            const lotNo = rec.purchase?.lotNo || rec.lotNo || "-";
            const invoiceNo = rec.sale?.invoiceNo || rec.invoiceNo || "-";
            const dateStr = rec.sale?.invoiceDate
                ? new Date(rec.sale.invoiceDate).toLocaleDateString("en-GB").replace(/\//g, "-")
                : rec.invoiceDate
                ? new Date(rec.invoiceDate).toLocaleDateString("en-GB").replace(/\//g, "-")
                : "-";
            const customerName = rec.sale?.customer?.name || rec.sale?.walkInName || rec.customerName || "-";
            const vegetableName = rec.purchase?.vegetable?.name || rec.vegetableName || "-";
            const supplierName = rec.purchase?.supplier?.name || rec.purchase?.cashSupplierName || rec.supplierName || "-";
            const qty = Number(rec.quantity ?? 0);
            const bags = rec.bags != null ? Number(rec.bags).toFixed(2) : "-";
            const totalAmt = Number(rec.total ?? 0);
            const rate = qty > 0 ? (totalAmt / qty).toFixed(2) : Number(rec.sellingRate ?? 0).toFixed(2);

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

            doc.font("Helvetica").fontSize(7.5).fillColor(COLORS.text);
            doc.text(lotNo,         cols.lotNo.x,     y + 4, { width: cols.lotNo.width - 2,     ellipsis: true, lineBreak: false });
            doc.text(vegetableName, cols.vegetable.x, y + 4, { width: cols.vegetable.width - 2, ellipsis: true, lineBreak: false });
            doc.text(invoiceNo,     cols.invoiceNo.x, y + 4, { width: cols.invoiceNo.width - 2, ellipsis: true, lineBreak: false });
            doc.text(dateStr,       cols.date.x,      y + 4, { width: cols.date.width - 2,      lineBreak: false });
            doc.text(customerName,  cols.customer.x,  y + 4, { width: cols.customer.width - 2,  ellipsis: true, lineBreak: false });

            doc.text(fmt(qty),      cols.qty.x,       y + 4, { width: cols.qty.width - 2,       align: "right", lineBreak: false });
            doc.text(bags,          cols.bags.x,      y + 4, { width: cols.bags.width - 2,      align: "right", lineBreak: false });
            doc.text(rate,          cols.rate.x,      y + 4, { width: cols.rate.width - 2,      align: "right", lineBreak: false });

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

            doc.font("Helvetica").fontSize(7.5).fillColor(COLORS.text);
            doc.text(supplierName,  cols.supplier.x,  y + 4, { width: cols.supplier.width - 2,  ellipsis: true, 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 += 10;
    }

    private static drawTotals(
        doc: PDFKit.PDFDocument,
        records: any[],
        pageWidth: number
    ) {
        const totalQty = records.reduce((s, r) => s + Number(r.quantity ?? 0), 0);
        const totalBags = records.reduce((s, r) => s + (r.bags != null ? Number(r.bags) : 0), 0);
        const totalAmt = records.reduce((s, r) => s + Number(r.total ?? 0), 0);

        const boxWidth = pageWidth * 0.42;
        const labelX   = PAGE_MARGIN + pageWidth - boxWidth;
        const valX     = labelX + boxWidth * 0.58;
        const valWidth = boxWidth * 0.42;

        const y0 = doc.y;

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

        doc.y = y0 + 6;

        doc.font("Helvetica").fontSize(8.5).fillColor(COLORS.text)
           .text("Total Quantity Sold (KG):", labelX, doc.y, { width: boxWidth * 0.58 });
        doc.font("Helvetica-Bold").fontSize(8.5).fillColor(COLORS.primary)
           .text(fmt(totalQty), valX, doc.y - 11.5, { width: valWidth, align: "right" });
        doc.y += 4;

        if (totalBags > 0) {
            doc.font("Helvetica").fontSize(8.5).fillColor(COLORS.text)
               .text("Total Bags Sold:", labelX, doc.y, { width: boxWidth * 0.58 });
            doc.font("Helvetica-Bold").fontSize(8.5).fillColor(COLORS.primary)
               .text(fmt(totalBags), valX, doc.y - 11.5, { width: valWidth, align: "right" });
            doc.y += 4;
        }

        doc.font("Helvetica-Bold").fontSize(9.5).fillColor(COLORS.primary);
        doc.text("Total Sales Amount:", labelX, doc.y, { width: boxWidth * 0.58 });
        doc.font("Helvetica-Bold").fontSize(9.5).fillColor(COLORS.primary)
           .text(`Rs. ${fmt(totalAmt)}`, valX, doc.y - 13, { width: valWidth, align: "right" });

        doc.y += 16;
    }

    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 lot-wise sales report.",
                PAGE_MARGIN,
                y,
                { width: pageWidth, align: "center" }
            );
    }
}
