/**
 * thermal_print.js
 * ─────────────────────────────────────────────────────────────────────────────
 * Include once on any page that needs thermal printing:
 *   <script src="thermal_print.js"></script>
 *
 * Public API:
 *   ThermalPrint.receipt(orderData)
 *   ThermalPrint.split(billsArray)
 *   ThermalPrint.kitchen(ticketsArray)
 *   ThermalPrint.browserOnly(text, title)
 *
 * Print path (automatic):
 *   1. POST to thermal_print.php (ePOS HTTP or raw port 9100)
 *   2. If network fails → opens browser print popup (80mm styled)
 */
window.ThermalPrint = (function () {
    'use strict';

    // ── CONFIG ────────────────────────────────────────────────────────────────
    // Change this to the absolute path where thermal_print.php lives on your server
    const ENDPOINT    = '/rooms/modules/calendar/thermal_print.php';
    const PAPER_WIDTH = 48;   // 80mm = 48 chars
    const PROP_NAME   = document.querySelector('meta[name="property-name"]')?.content
                        || 'THE PROPERTY';

    // ── Text helpers (for browser fallback) ───────────────────────────────────
    function pad(left, right, width) {
        left  = String(left  ?? '');
        right = String(right ?? '');
        const space = Math.max(1, width - left.length - right.length);
        return left + ' '.repeat(space) + right;
    }
    function center(text, width) {
        const p = Math.max(0, Math.floor((width - String(text).length) / 2));
        return ' '.repeat(p) + text;
    }
    function divider(char, width) { return (char || '-').repeat(width || PAPER_WIDTH); }
    function money(v) { return (parseFloat(v) || 0).toFixed(2); }
    function esc(s) {
        return String(s ?? '').replace(/[&<>"']/g, c =>
            ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'})[c]);
    }

    // ── Plain-text builders (browser fallback) ────────────────────────────────
    function textReceipt(t) {
        const w   = PAPER_WIDTH;
        const now = new Date().toLocaleString();
        const out = [];
        out.push(divider('=', w));
        out.push(center(PROP_NAME.toUpperCase(), w));
        out.push(divider('=', w));
        if (t.order_no) out.push('Order:   ' + t.order_no);
        if (t.table)    out.push('Table:   ' + t.table);
        if (t.guest)    out.push('Guest:   ' + t.guest);
        if (t.cashier)  out.push('Cashier: ' + t.cashier);
        out.push('Date:    ' + (t.date || now));
        out.push(divider('-', w));
        let sub = 0;
        (t.items || []).forEach(item => {
            if ((item.status || 'active') !== 'active') return;
            const qty    = parseFloat(item.qty || 1) || 1;
            const amount = parseFloat(item.amount || 0);
            sub += amount;
            const label = (qty !== 1 ? (Number.isInteger(qty) ? qty : qty.toFixed(2)) + ' x ' : '') + (item.name || 'Item');
            out.push(pad(label.substring(0, w - 10), money(amount), w));
            if (item.notes) out.push('  * ' + item.notes);
        });
        out.push(divider('-', w));
        if (t.tax && parseFloat(t.tax) > 0) {
            out.push(pad('Subtotal', money(t.subtotal || sub), w));
            out.push(pad('Tax',      money(t.tax), w));
        }
        out.push(pad('TOTAL', money(t.total || sub), w));
        if (t.payments && t.payments.length) {
            out.push(divider('-', w));
            t.payments.forEach(p => {
                out.push(pad((p.method || '').toUpperCase(), money(p.amount || 0), w));
                if (p.reference) out.push('  Ref: ' + p.reference);
            });
        }
        if (t.surcharge && parseFloat(t.surcharge) > 0)
            out.push('  * Incl. 3% card surcharge ' + money(t.surcharge));
        out.push(divider('=', w));
        out.push(center('Thank you for your visit!', w));
        out.push(''); out.push('');
        return out.join('\n');
    }

    function textSplit(t) {
        const w   = PAPER_WIDTH;
        const now = new Date().toLocaleString();
        const out = [];
        out.push(divider('=', w));
        out.push(center(PROP_NAME.toUpperCase(), w));
        out.push(center('-- SPLIT BILL --', w));
        out.push(divider('=', w));
        if (t.order_no) out.push('Order:  ' + t.order_no);
        if (t.payer)    out.push('Payer:  ' + t.payer);
        if (t.method)   out.push('Method: ' + t.method);
        out.push('Date:   ' + (t.date || now));
        out.push(divider('-', w));
        let sub = 0;
        (t.items || []).forEach(item => {
            const qty    = parseFloat(item.qty || 1) || 1;
            const amount = parseFloat(item.amount || 0);
            sub += amount;
            const label = (qty !== 1 ? (Number.isInteger(qty) ? qty : qty.toFixed(2)) + ' x ' : '') + (item.name || 'Item');
            out.push(pad(label.substring(0, w - 10), money(amount), w));
        });
        out.push(divider('-', w));
        out.push(pad('AMOUNT DUE', money(t.total || sub), w));
        if (t.surcharge && parseFloat(t.surcharge) > 0)
            out.push(pad('  incl. 3% surcharge', money(t.surcharge), w));
        out.push(divider('=', w));
        out.push(center('Thank you!', w));
        out.push(''); out.push('');
        return out.join('\n');
    }

    function textKitchen(t) {
        const w    = PAPER_WIDTH;
        const role = (t.station || 'KITCHEN').toUpperCase();
        const out  = [];
        out.push(divider('=', w));
        out.push(center('*** ' + role + ' TICKET ***', w));
        out.push(divider('=', w));
        if (t.order_no) out.push('ORDER:  ' + t.order_no);
        if (t.table)    out.push('Table:  ' + t.table);
        if (t.covers)   out.push('Covers: ' + t.covers);
        out.push('Time:   ' + (t.date || new Date().toLocaleTimeString()));
        out.push(divider('=', w));
        (t.items || []).forEach(item => {
            const qty  = parseFloat(item.qty || 1) || 1;
            out.push(' ' + (Number.isInteger(qty) ? qty : qty.toFixed(1)) + ' x ' + (item.name || 'Item').toUpperCase());
            if (item.seat)  out.push('   Seat:  ' + item.seat);
            if (item.notes) out.push('   ** '    + item.notes);
        });
        out.push(divider('=', w));
        out.push(''); out.push('');
        return out.join('\n');
    }

    // ── Browser print popup ───────────────────────────────────────────────────
    function browserPrint(texts, title) {
        const combined = Array.isArray(texts)
            ? texts.join('\n\n' + '─'.repeat(PAPER_WIDTH) + '\n\n')
            : String(texts || '');

        const html = `<!DOCTYPE html><html><head><meta charset="UTF-8">
<title>${title || 'Print'}</title>
<style>
  *{margin:0;padding:0;box-sizing:border-box}
  body{font-family:'Courier New',Courier,monospace;font-size:11px;line-height:1.3;padding:4mm}
  pre{white-space:pre-wrap;word-break:break-all;font-family:inherit;font-size:inherit}
  @media print{@page{size:80mm auto;margin:2mm}body{padding:0}}
</style></head><body>
<pre>${combined.replace(/[&<>"]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'})[c])}</pre>
<script>window.onload=function(){window.print();setTimeout(function(){window.close();},1200);}<\/script>
</body></html>`;

        const w = window.open('', '_blank', 'width=340,height=600,scrollbars=yes');
        if (w) { w.document.write(html); w.document.close(); }
        else   { alert('Popup blocked — please allow popups to print.'); }
    }

    // ── Toast notification ────────────────────────────────────────────────────
    function toast(message, type) {
        type = type || 'info';
        let el = document.getElementById('thermalPrintToast');
        if (!el) {
            el = document.createElement('div');
            el.id = 'thermalPrintToast';
            el.style.cssText = 'position:fixed;bottom:20px;right:20px;z-index:99999;max-width:320px;'
                + 'padding:10px 14px;border-radius:10px;font-size:13px;font-weight:700;'
                + 'box-shadow:0 8px 24px rgba(0,0,0,.22);transition:opacity .3s;opacity:0;pointer-events:none;';
            document.body.appendChild(el);
        }
        const colors = {
            success: ['#166534','#dcfce7'],
            error:   ['#991b1b','#fee2e2'],
            info:    ['#1e3a8a','#dbeafe'],
        };
        const [fg, bg] = colors[type] || colors.info;
        el.style.background = bg;
        el.style.color      = fg;
        el.textContent      = message;
        el.style.opacity    = '1';
        clearTimeout(el._t);
        el._t = setTimeout(() => { el.style.opacity = '0'; }, 3500);
    }

    // ── Network print via thermal_print.php ───────────────────────────────────
    async function networkPrint(tickets) {
        const csrfInput = document.querySelector('input[name="_token"], input[name="csrf_token"]');
        const headers   = { 'Content-Type': 'application/json' };
        if (csrfInput) headers['X-CSRF-TOKEN'] = csrfInput.value;

        const resp = await fetch(ENDPOINT, {
            method:      'POST',
            headers:     headers,
            credentials: 'same-origin',
            body:        JSON.stringify({ tickets }),
        });

        if (!resp.ok) throw new Error('HTTP ' + resp.status + ' from ' + ENDPOINT);
        return await resp.json();
    }

    // ── Main dispatcher ───────────────────────────────────────────────────────
    async function printTickets(tickets, fallbackTexts, title) {
        toast('Sending to printer…', 'info');
        try {
            const data = await networkPrint(tickets);

            if (data.ok) {
                const method = data.method || 'network';
                toast('✓ Printed via ' + method, 'success');
                return;
            }

            // Partial failure — browser-print the failed ones
            const failed = [];
            (data.results || []).forEach((r, i) => {
                if (!r.ok && fallbackTexts[i]) failed.push(fallbackTexts[i]);
            });

            if (failed.length) {
                toast('Printer unreachable — opening browser print…', 'error');
                browserPrint(failed, title);
            } else {
                toast('✓ Printed (partial)', 'success');
            }

        } catch (err) {
            console.error('ThermalPrint error:', err);
            toast('Network error — opening browser print…', 'error');
            browserPrint(fallbackTexts, title);
        }
    }

    // ── Public API ────────────────────────────────────────────────────────────
    return {

        /**
         * Print a receipt.
         * @param {Object} orderData  { order_no, table, guest, cashier, date,
         *                             items:[{name,qty,amount,status,notes}],
         *                             subtotal, tax, total,
         *                             payments:[{method,amount,reference}],
         *                             surcharge }
         */
        receipt(orderData) {
            const t        = { type: 'receipt', ...orderData };
            const fallback = textReceipt(t);
            return printTickets([t], [fallback], 'Receipt');
        },

        /**
         * Print split bills.
         * @param {Array} bills  [{ payer, method, items, total, surcharge, order_no }]
         */
        split(bills) {
            const tickets  = bills.map(b => ({ type: 'split', ...b }));
            const fallback = bills.map(b => textSplit(b));
            return printTickets(tickets, fallback, 'Split Bills');
        },

        /**
         * Print kitchen / bar tickets.
         * @param {Array} tickets  [{ station, order_no, table, covers, items:[{name,qty,seat,notes}] }]
         */
        kitchen(tickets) {
            const decorated = tickets.map(t => ({
                type: (t.station || '').toLowerCase() === 'bar' ? 'bar' : 'kitchen',
                ...t,
            }));
            const fallback = tickets.map(t => textKitchen(t));
            return printTickets(decorated, fallback, 'Kitchen Tickets');
        },

        /**
         * Browser print only — no network attempt.
         */
        browserOnly(texts, title) {
            browserPrint(Array.isArray(texts) ? texts : [texts], title || 'Print');
        },
    };

})();
