/** @odoo-module */

import { patch } from "@web/core/utils/patch";
import { ReceiptScreen } from "@point_of_sale/app/screens/receipt_screen/receipt_screen";

const RECEIPT_COLUMNS = 42;
const NEWLINE = "\r\n";

function normalizeReceiptText(text) {
    return (text || "")
        .replace(/\u00a0/g, " ")
        .replace(/[ \t]+/g, " ")
        .split("\n")
        .map((line) => line.trim())
        .filter(Boolean);
}

function wrapLine(line, width = RECEIPT_COLUMNS) {
    if (line.length <= width) {
        return [line];
    }
    const wrapped = [];
    let remaining = line;
    while (remaining.length > width) {
        let breakpoint = remaining.lastIndexOf(" ", width);
        if (breakpoint <= 0) {
            breakpoint = width;
        }
        wrapped.push(remaining.slice(0, breakpoint).trimEnd());
        remaining = remaining.slice(breakpoint).trimStart();
    }
    if (remaining) {
        wrapped.push(remaining);
    }
    return wrapped;
}

function money(value, currency) {
    const amount = Number(value || 0).toFixed(2);
    return currency?.symbol ? `${currency.symbol}${amount}` : amount;
}

function leftRight(left, right, width = RECEIPT_COLUMNS) {
    const cleanLeft = String(left || "");
    const cleanRight = String(right || "");
    const space = Math.max(1, width - cleanLeft.length - cleanRight.length);
    return `${cleanLeft}${" ".repeat(space)}${cleanRight}`;
}

function buildReceiptLinesFromOrder(order) {
    const currency = order?.pos?.currency;
    const lines = [];
    const company = order?.pos?.company;
    const client = order?.get_partner?.();

    if (company?.name) {
        lines.push(company.name);
    }
    if (company?.phone) {
        lines.push(company.phone);
    }
    lines.push("-".repeat(RECEIPT_COLUMNS));

    const receiptNumber = order?.name || order?.uid || "";
    if (receiptNumber) {
        lines.push(`Receipt: ${receiptNumber}`);
    }
    lines.push(new Date().toLocaleString());
    if (client?.name) {
        lines.push(`Customer: ${client.name}`);
    }
    lines.push("-".repeat(RECEIPT_COLUMNS));

    for (const orderline of order?.get_orderlines?.() || []) {
        const product = orderline.get_product?.();
        const name = product?.display_name || product?.name || "";
        const qty = orderline.get_quantity?.() || 0;
        const total = orderline.get_price_with_tax?.() ?? orderline.get_display_price?.() ?? 0;
        for (const wrapped of wrapLine(name, RECEIPT_COLUMNS)) {
            lines.push(wrapped);
        }
        lines.push(leftRight(`  ${qty} x`, money(total, currency)));
    }

    lines.push("-".repeat(RECEIPT_COLUMNS));
    lines.push(leftRight("TOTAL", money(order?.get_total_with_tax?.(), currency)));
    const tax = order?.get_total_tax?.();
    if (tax) {
        lines.push(leftRight("Tax", money(tax, currency)));
    }
    const change = order?.get_change?.();
    if (change) {
        lines.push(leftRight("Change", money(change, currency)));
    }
    lines.push("-".repeat(RECEIPT_COLUMNS));
    lines.push("Thank you");
    return lines;
}

function buildReceiptLines(receiptElement, order) {
    const domLines = normalizeReceiptText(receiptElement?.innerText || "");
    if (domLines.length > 1) {
        return domLines;
    }
    return buildReceiptLinesFromOrder(order);
}

function buildEscPosReceipt(receiptElement, order) {
    const ESC = "\x1B";
    const GS = "\x1D";
    const lines = buildReceiptLines(receiptElement, order);
    const body = lines.flatMap((line) => wrapLine(line)).join(NEWLINE);

    return [
        ESC + "@", // Initialize printer
        ESC + "a" + "\x00", // Left align
        body,
        NEWLINE + NEWLINE + NEWLINE,
        GS + "V" + "\x00", // Full cut on Epson-compatible printers
    ].join("");
}

patch(ReceiptScreen.prototype, {
    async printReceipt() {
        if (this.pos.config.use_qz_printer && this.pos.config.qz_printer_name) {
            const rawPrintingEnabled = window.localStorage?.getItem("dine360_qz_raw_enabled") === "1";
            if (!rawPrintingEnabled) {
                console.warn(
                    "QZ raw receipt printing is disabled. Set localStorage.dine360_qz_raw_enabled = '1' only while testing a raw ESC/POS printer queue."
                );
                return super.printReceipt(...arguments);
            }

            try {
                if (!window.qz) {
                    console.error("QZ Tray library not loaded.");
                    return false;
                }

                if (!qz.websocket.isActive()) {
                    await qz.websocket.connect({ retries: 2, delay: 1 });
                }

                const printerName = this.pos.config.qz_printer_name;
                const config = qz.configs.create(printerName, {
                    encoding: "CP437",
                    spool: { end: "\n" },
                });

                const receiptElement = document.querySelector(".pos-receipt") || document.querySelector(".pos-receipt-container");
                if (!receiptElement) {
                    return false;
                }

                const printData = buildEscPosReceipt(receiptElement, this.currentOrder);

                await qz.print(config, [printData]);

                if (this.currentOrder) {
                    this.currentOrder._printed = true;
                }
                
                return true;

            } catch (err) {
                console.error("QZ Tray Print Error:", err);
                this.env.services.popup.add("ErrorPopup", {
                    title: "QZ Tray Printer Error",
                    body: "Failed to connect to local QZ Tray or printer. Make sure QZ Tray is running.",
                });
                return false;
            }
        } else {
            // Fallback to default Odoo print behavior
            return super.printReceipt(...arguments);
        }
    }
});
