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

const PAGE_MARGIN = 40;

export class CustomerReceiptPdf {
    static async generate(
        receipts: any[],
        res: Response,
        filters?: { startDate?: string; endDate?: string; search?: string }
    ) {
        const doc = new PDFDocument({ size: "A4", margin: PAGE_MARGIN, bufferPages: true });

        res.setHeader("Content-Type", "application/pdf");
        res.setHeader("Content-Disposition", `attachment; filename="customer-receipts-${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, "CUSTOMER RECEIPTS REPORT");

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

        doc.end();
    }

    private static drawFilterLine(
        doc: PDFKit.PDFDocument,
        pageWidth: number,
        filters?: { startDate?: string; endDate?: string; search?: string }
    ) {
        const parts: string[] = [];
        if (filters?.startDate) parts.push(`From: ${new Date(filters.startDate).toLocaleDateString("en-GB").replace(/\//g, "-")}`);
        if (filters?.endDate) parts.push(`To: ${new Date(filters.endDate).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, receipts: any[], pageWidth: number) {
        const cols = {
            no:          { x: PAGE_MARGIN,                      width: pageWidth * 0.05 },
            date:        { x: PAGE_MARGIN + pageWidth * 0.05,   width: pageWidth * 0.14 },
            customer:    { x: PAGE_MARGIN + pageWidth * 0.19,   width: pageWidth * 0.25 },
            mode:        { x: PAGE_MARGIN + pageWidth * 0.44,   width: pageWidth * 0.13 },
            reference:   { x: PAGE_MARGIN + pageWidth * 0.57,   width: pageWidth * 0.18 },
            amount:      { x: PAGE_MARGIN + pageWidth * 0.75,   width: pageWidth * 0.25 },
        };

        const rowHeight = 24;
        const headerH = 26;

        const drawHeader = () => {
            const y = doc.y;
            doc.font("Helvetica-Bold").fontSize(8.5).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("CUSTOMER",   cols.customer.x,  y + 6, { width: cols.customer.width })
                .text("MODE",       cols.mode.x,      y + 6, { width: cols.mode.width,       align: "center" })
                .text("REFERENCE",  cols.reference.x, y + 6, { width: cols.reference.width })
                .text("AMOUNT",     cols.amount.x,    y + 6, { width: cols.amount.width - 6, align: "right" });

            doc.y = y + headerH;
            doc.moveTo(PAGE_MARGIN, doc.y).lineTo(PAGE_MARGIN + pageWidth, doc.y)
                .strokeColor(COLORS.primary).lineWidth(1).stroke();
            doc.y += 4;
        };

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

        drawHeader();

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

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

            const dateStr = r.receiptDate ? new Date(r.receiptDate).toLocaleDateString("en-GB").replace(/\//g, "-") : "-";
            const customerName = r.customer?.name || "-";

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

            doc.font("Helvetica").fontSize(9).fillColor(COLORS.text);
            doc.text(dateStr,        cols.date.x,      y + 5, { width: cols.date.width });
            doc.text(customerName,   cols.customer.x,  y + 5, { width: cols.customer.width - 4, ellipsis: true, lineBreak: false });
            doc.text(r.paymentMode || "-", cols.mode.x, y + 5, { width: cols.mode.width, align: "center" });
            doc.text(r.referenceNo || "-", cols.reference.x, y + 5, { width: cols.reference.width - 4, ellipsis: true, lineBreak: false });

            doc.font("Helvetica-Bold").fontSize(9).fillColor(COLORS.primary)
                .text(this.formatCurrency(r.amount), cols.amount.x, y + 5, { width: cols.amount.width - 6, align: "right" });

            doc.y = y + rowHeight;
        });

        doc.moveTo(PAGE_MARGIN, doc.y).lineTo(PAGE_MARGIN + pageWidth, doc.y)
            .strokeColor(COLORS.border).lineWidth(0.5).stroke();
        doc.y += 14;
    }

    private static drawTotals(doc: PDFKit.PDFDocument, receipts: any[], pageWidth: number) {
        const total = receipts.reduce((sum, r) => sum + Number(r.amount ?? 0), 0);
        const boxWidth = pageWidth * 0.38;
        const labelX = PAGE_MARGIN + pageWidth - boxWidth;
        const y = doc.y;

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

        doc.font("Helvetica-Bold").fontSize(11).fillColor(COLORS.primary)
            .text("TOTAL RECEIPTS:", labelX, doc.y, { width: boxWidth * 0.58 })
            .text(this.formatCurrency(total), labelX, doc.y - 13.5, { width: boxWidth, align: "right" });

        doc.y += 18;
    }

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

    private static formatCurrency(val: any): string {
        const num = Number(val);
        return isNaN(num) ? "Rs. 0.00" : `Rs. ${num.toFixed(2)}`;
    }
}
