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 = 40;

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

        res.setHeader("Content-Type", "application/pdf");
        res.setHeader(
            "Content-Disposition",
            `attachment; filename="fast-billings-${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, "FAST BILLING REPORT");

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

        doc.end();
    }

    private static drawFilterLine(
        doc: PDFKit.PDFDocument,
        pageWidth: number,
        filters?: { startDate?: string | undefined; endDate?: string | undefined; search?: string | undefined }
    ) {
        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,
        billings: any[],
        pageWidth: number
    ) {
        const cols = {
            no: { x: PAGE_MARGIN, width: pageWidth * 0.06 },
            billNo: { x: PAGE_MARGIN + pageWidth * 0.06, width: pageWidth * 0.16 },
            date: { x: PAGE_MARGIN + pageWidth * 0.22, width: pageWidth * 0.14 },
            customer: { x: PAGE_MARGIN + pageWidth * 0.36, width: pageWidth * 0.22 },
            items: { x: PAGE_MARGIN + pageWidth * 0.58, width: pageWidth * 0.10 },
            remarks: { x: PAGE_MARGIN + pageWidth * 0.68, width: pageWidth * 0.16 },
            total: { x: PAGE_MARGIN + pageWidth * 0.84, width: pageWidth * 0.16 },
        };

        const rowHeight = 22;
        const headerH = 24;

        const drawTableHeader = () => {
            const y = doc.y;
            doc
                .font("Helvetica-Bold")
                .fontSize(8.5)
                .fillColor(COLORS.primary)
                .text("SL#", cols.no.x, y + 6, { width: cols.no.width, align: "center" })
                .text("BILL NO", cols.billNo.x + 4, y + 6, { width: cols.billNo.width - 4 })
                .text("DATE", cols.date.x + 4, y + 6, { width: cols.date.width - 4 })
                .text("CUSTOMER", cols.customer.x + 4, y + 6, { width: cols.customer.width - 4 })
                .text("ITEMS", cols.items.x, y + 6, { width: cols.items.width, align: "center" })
                .text("REMARKS", cols.remarks.x + 4, y + 6, { width: cols.remarks.width - 4 })
                .text("TOTAL", cols.total.x, y + 6, { width: cols.total.width - 6, align: "right" });

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

            doc.y = y + headerH + 2;
        };

        drawTableHeader();

        billings.forEach((bill, index) => {
            if (doc.y + rowHeight > doc.page.height - PAGE_MARGIN - 30) {
                doc.addPage();
                doc.y = PAGE_MARGIN;
                drawTableHeader();
            }

            const y = doc.y;

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

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

            const itemCount = bill.items ? bill.items.length : 0;
            const remarks = bill.remarks || "-";

            doc
                .font("Helvetica")
                .fontSize(8.5)
                .fillColor(COLORS.text)
                .text(`${index + 1}`, cols.no.x, y + 5, { width: cols.no.width, align: "center" })
                .text(bill.billNo || "-", cols.billNo.x + 4, y + 5, { width: cols.billNo.width - 4, ellipsis: true })
                .text(dateStr, cols.date.x + 4, y + 5, { width: cols.date.width - 4 })
                .text(bill.customerName || "-", cols.customer.x + 4, y + 5, { width: cols.customer.width - 4, ellipsis: true })
                .text(`${itemCount}`, cols.items.x, y + 5, { width: cols.items.width, align: "center" })
                .text(remarks, cols.remarks.x + 4, y + 5, { width: cols.remarks.width - 4, ellipsis: true })
                .text(this.formatCurrency(bill.totalAmount), cols.total.x, y + 5, { width: cols.total.width - 6, align: "right" });

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

            doc.y = y + rowHeight;
        });

        doc.y += 10;
    }

    private static drawTotals(
        doc: PDFKit.PDFDocument,
        billings: any[],
        pageWidth: number
    ) {
        if (doc.y + 40 > doc.page.height - PAGE_MARGIN - 30) {
            doc.addPage();
            doc.y = PAGE_MARGIN;
        }

        const total = billings.reduce((sum, b) => sum + Number(b.totalAmount || 0), 0);

        const boxWidth = 200;
        const boxX = PAGE_MARGIN + pageWidth - boxWidth;

        doc
            .rect(boxX, doc.y, boxWidth, 24)
            .fillColor(COLORS.rowAlt)
            .fill()
            .strokeColor(COLORS.border)
            .lineWidth(1)
            .stroke();

        doc
            .font("Helvetica-Bold")
            .fontSize(9)
            .fillColor(COLORS.primary)
            .text("Grand Total:", boxX + 10, doc.y + 7, { width: 90 })
            .text(this.formatCurrency(total), boxX + 100, doc.y + 7, {
                width: 90,
                align: "right",
            });

        doc.y += 34;
    }

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

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