/** @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?.();
    const table = order?.table;
    const cashier = order?.employee || order?.pos?.get_cashier?.();

    // 1. HEADER (Centered-ish)
    if (company?.name) {
        lines.push(company.name.toUpperCase());
    }
    if (company?.street) lines.push(company.street);
    if (company?.city) lines.push(company.city);
    if (company?.phone) lines.push(`Tel: ${company.phone}`);
    
    // Custom Odoo Header
    if (order?.pos?.config?.receipt_header) {
        lines.push(order.pos.config.receipt_header);
    }
    lines.push("-".repeat(RECEIPT_COLUMNS));

    // 2. ORDER INFO
    const receiptNumber = order?.name || "";
    if (receiptNumber) lines.push(`Order: ${receiptNumber}`);
    
    if (table) {
        lines.push(`TABLE: ${table.name}`.padEnd(20) + `GUESTS: ${order.customer_count || 1}`);
    }
    if (cashier) {
        lines.push(`SERVER: ${cashier.name}`);
    }
    lines.push(`DATE: ${new Date().toLocaleString()}`);
    if (client) {
        lines.push(`CUSTOMER: ${client.name}`);
    }
    
    lines.push("=".repeat(RECEIPT_COLUMNS));
    lines.push(leftRight("ITEM", "PRICE"));
    lines.push("-".repeat(RECEIPT_COLUMNS));

    // 3. ORDER LINES
    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 priceUnit = orderline.get_unit_display_price?.() || 0;
        const total = orderline.get_price_with_tax?.() || 0;

        // "Qty x Name" on left, "Total" on right
        const itemLabel = `${qty} x ${name}`;
        const itemPrice = money(total, currency);
        
        if (itemLabel.length + itemPrice.length + 1 > RECEIPT_COLUMNS) {
            lines.push(itemLabel);
            lines.push(itemPrice.padStart(RECEIPT_COLUMNS));
        } else {
            lines.push(leftRight(itemLabel, itemPrice));
        }
        
        // Show unit price if qty > 1
        if (qty > 1) {
            lines.push(`  @ ${money(priceUnit, currency)}`);
        }
    }

    // 4. TOTALS
    lines.push("=".repeat(RECEIPT_COLUMNS));
    lines.push(leftRight("SUBTOTAL", money(order?.get_total_without_tax?.(), currency)));
    
    const tax = order?.get_total_tax?.();
    if (tax) {
        lines.push(leftRight("TAX", money(tax, currency)));
    }
    
    lines.push("-".repeat(RECEIPT_COLUMNS));
    lines.push(leftRight("TOTAL", money(order?.get_total_with_tax?.(), currency)));
    
    const change = order?.get_change?.();
    if (change) {
        lines.push(leftRight("CHANGE", money(change, currency)));
    }
    
    lines.push("-".repeat(RECEIPT_COLUMNS));
    
    // Custom Odoo Footer
    if (order?.pos?.config?.receipt_footer) {
        lines.push(order.pos.config.receipt_footer);
    }
    
    lines.push("THANK YOU FOR DINING WITH US!");
    lines.push("PLEASE VISIT AGAIN");
    lines.push(NEWLINE);
    
    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";
    let lines = buildReceiptLines(receiptElement, order);
    
    // Safety mechanism: limit receipt length to prevent runaway printing
    if (lines.length > 150) {
        console.warn("Receipt is suspiciously long, truncating to 150 lines to prevent runaway printing.");
        lines.length = 150;
        lines.push("-".repeat(RECEIPT_COLUMNS));
        lines.push("TRUNCATED FOR SAFETY");
    }

    const body = lines.flatMap((line) => wrapLine(line)).join(NEWLINE);

    console.log("Cutter command run: Preparing ESC/POS data with feed and partial cut.");

    return [
        ESC + "@", // Initialize printer
        ESC + "a" + "\x00", // Left align
        body,
        NEWLINE + NEWLINE + NEWLINE + NEWLINE + NEWLINE,
        GS + "V" + "\x42" + "\x00", // Feed paper to cutting position and perform partial cut (standard ESC/POS)
    ].join("");
}

patch(ReceiptScreen.prototype, {
    async printReceipt() {
        if (this.pos.config.use_qz_printer && this.pos.config.qz_printer_name) {
            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);
        }
    }
});
