<script>
    // Ensure a single global PRODUCTS array to avoid duplicate declaration errors
    if (typeof window.PRODUCTS === 'undefined') {
        window.PRODUCTS = <?php echo json_encode($productsJs ?? [], 15, 512) ?>;
    }

    // Ensure a single global CUSTOMERS array
    if (typeof window.CUSTOMERS === 'undefined') {
        window.CUSTOMERS = <?php echo json_encode($customersJs ?? [], 15, 512) ?>;
    }

    // Ensure a PRODUCT_STOCKS map (product_id => [{branch_id, branch_name, qty}, ...]) for front-end lookup
    if (typeof window.PRODUCT_STOCKS === 'undefined') {
        window.PRODUCT_STOCKS = <?php echo json_encode($stocksJs ?? (object)[], 15, 512) ?>;
    }

    // Fallback: if server didn't inject customers or it's empty, build from the hidden select in DOM
    try {
        if (!window.CUSTOMERS || !window.CUSTOMERS.length) {
            window.CUSTOMERS = [];
            const optList = document.querySelectorAll('select[name="customer_id"] option');
            if (optList && optList.length) {
                optList.forEach(o => {
                    const v = o.value;
                    const t = (o.text || '').trim();
                    const contact = (o.dataset && o.dataset.contact) ? o.dataset.contact : (o.getAttribute('data-contact') || '');
                    if (v) window.CUSTOMERS.push({ id: v, name: t, contact: contact });
                });
            }
            try { console.debug('Built window.CUSTOMERS fallback, count:', window.CUSTOMERS.length, window.CUSTOMERS.slice(0,5)); } catch(e){}
        }
    } catch(e){ console.warn('Error building customers fallback', e); }

    // Toggle to enable/disable keyboard shortcuts on this create page.
    // Set to false to remove all key handlers as requested.
    const ENABLE_INVOICE_KEYBOARD = false;

    // Determine if this is the edit page based on URL
    const isEdit = window.location.pathname.includes('/edit');

    function attachKeydown(el, handler){
        try {
            // Always attach the handler for input-level dropdown navigation
            // (keep ENABLE_INVOICE_KEYBOARD to control global shortcuts only)
            if(!el) return;
            el.addEventListener('keydown', handler);
        } catch(e){}
        
        // Loan UI and calculation helpers
        try {
            const loanCard = document.getElementById('loanOptionsCard');
            const loanInputs = document.getElementById('loanInputs');
            const modeCash = document.getElementById('mode_cash');
            const modeLoan = document.getElementById('mode_loan');
            const downEl = document.getElementById('loan_downpayment');
            const monthsEl = document.getElementById('loan_months');
            const monthlyDisplay = document.getElementById('loan_monthly_amount_display');
            const scheduleTableBody = document.querySelector('#loanScheduleTable tbody');

            // Keep the loan options card hidden by default; do not force it visible here.
            // (Visibility will be controlled by the invoice mode radio handlers elsewhere.)
            // if(loanCard) loanCard.style.display = 'block';

            function computeLoanSchedule(netTotal, down, periods, frequency){
                // periods: number of installments
                // frequency: 'month' or 'week'
                netTotal = parseFloat(netTotal) || 0;
                down = parseFloat(down) || 0;
                periods = parseInt(periods) || 1;
                frequency = (frequency || 'month').toString();
                const remaining = Math.max(0, netTotal - down);
                const base = periods > 0 ? (remaining / periods) : remaining;
                const unit = Math.round(base * 100) / 100;
                const schedule = [];
                let distributed = 0;

                // Determine start date for computing due dates: use invoice date_time if present else today
                let startDateVal = document.getElementById('date_time')?.value || null;
                let startDate = startDateVal ? new Date(startDateVal) : new Date();

                // Normalize to midnight for consistent date strings
                startDate.setHours(0,0,0,0);

                for(let i=1;i<=periods;i++){
                    let amt = (i === periods) ? parseFloat((remaining - distributed).toFixed(2)) : parseFloat(unit.toFixed(2));
                    // compute due date: first installment due one period after invoice date
                    let due = new Date(startDate.getTime());
                    if(frequency === 'week'){
                        due.setDate(due.getDate() + (7 * i));
                    } else {
                        // default month
                        const monthIndex = due.getMonth() + i;
                        due.setMonth(monthIndex);
                    }
                    // format YYYY-MM-DD
                    const yyyy = due.getFullYear();
                    const mm = String(due.getMonth() + 1).padStart(2, '0');
                    const dd = String(due.getDate()).padStart(2, '0');
                    const dueStr = `${yyyy}-${mm}-${dd}`;
                    schedule.push({ installment: i, amount: amt, due_date: dueStr });
                    distributed += amt;
                }
                return schedule;
            }

            function updateLoanUI(){
                const mode = document.querySelector('input[name="invoice_mode"]:checked')?.value || 'cash';
                if(mode === 'loan'){
                    if(loanInputs) loanInputs.style.display = 'block';
                    const netTotal = parseFloat((document.getElementById('summary_nettotal')?.innerText || '0')) || 0;
                    const down = parseFloat(downEl?.value || 0) || 0;
                    const months = parseInt(monthsEl?.value || 1) || 1;
                    const frequency = (document.getElementById('loan_frequency')?.value) || 'month';
                    const schedule = computeLoanSchedule(netTotal, down, months, frequency);
                    const monthly = schedule.length ? schedule[0].amount : 0;
                    if(monthlyDisplay) monthlyDisplay.value = parseFloat(monthly || 0).toFixed(2);
                    if(scheduleTableBody){
                        scheduleTableBody.innerHTML = '';
                        schedule.forEach(s => {
                            const tr = document.createElement('tr');
                            const td1 = document.createElement('td'); td1.innerText = s.installment;
                            const td2 = document.createElement('td'); td2.innerText = parseFloat(s.amount).toFixed(2);
                            const td3 = document.createElement('td'); td3.innerText = s.due_date || '';
                            tr.appendChild(td1); tr.appendChild(td2); tr.appendChild(td3);
                            scheduleTableBody.appendChild(tr);
                        });
                    }
                } else {
                    if(loanInputs) loanInputs.style.display = 'none';
                }
            }

            try { if(modeCash) modeCash.addEventListener('change', updateLoanUI); } catch(e){}
            try { if(modeLoan) modeLoan.addEventListener('change', updateLoanUI); } catch(e){}
            try { if(downEl) downEl.addEventListener('input', updateLoanUI); } catch(e){}
            try { if(monthsEl) monthsEl.addEventListener('input', updateLoanUI); } catch(e){}
            try { const freqEl = document.getElementById('loan_frequency'); if(freqEl) freqEl.addEventListener('change', updateLoanUI); } catch(e){}
            try { const summaryN = document.getElementById('summary_nettotal'); if(summaryN) new MutationObserver(updateLoanUI).observe(summaryN, { childList: true, characterData: true, subtree: true }); } catch(e){}
            setTimeout(updateLoanUI, 100);
        } catch(e){ console.warn('Loan UI init error', e); }
    }

    // Track the last selected price market so Add actions can use it
    try { window.SELECTED_PRICE_MARKET = null; } catch(e){}

    // Helper to open the selling-price dropdown for the currently selected product (used when selling input is focused)
    function openSellingDropdown(){
        try {
            const sellInput = document.getElementById('product_selling');
            if(!sellInput) return;
            // remove existing dropdown
            const existing = document.getElementById('selling_price_dropdown'); if(existing) existing.remove();

            // try to resolve the product for which to show prices
            let prodForPrices = window.selectedProduct || null;
            if(!prodForPrices){
                const searchVal = (document.getElementById('product_search') || {}).value || '';
                if(searchVal){
                    prodForPrices = findByBarcode(searchVal) || (window.PRODUCTS || []).find(p => (p.name||'').toLowerCase() === searchVal.toLowerCase());
                }
            }

            let arr = [];
            if (prodForPrices) {
                try {
                    arr = window.PRICES?.[prodForPrices.id] || window.PRICES?.[String(prodForPrices.id)] || [];
                    if (!arr.length && Array.isArray(window.PRICES)) {
                        arr = window.PRICES.filter(pr => String(pr.product_id) === String(prodForPrices.id));
                    }
                } catch(e){ arr = []; }
            }
            if(!arr || !arr.length) return;

            const dd = document.createElement('div');
            dd.id = 'selling_price_dropdown';
            dd.className = 'list-group shadow';
            dd.style.position = 'absolute';
            dd.style.zIndex = 2000;
            const rect = sellInput.getBoundingClientRect();
            dd.style.left = (rect.left + window.scrollX) + 'px';
            dd.style.top = (rect.bottom + window.scrollY) + 'px';
            dd.style.minWidth = (rect.width) + 'px';

            let focused = 0; // Start with first item highlighted
            arr.forEach((pr, i) => {
                const btn = document.createElement('button');
                btn.type = 'button';
                btn.className = 'list-group-item list-group-item-action' + (i === 0 ? ' active' : '');
                const sell = (parseFloat(pr.selling_price)||0).toFixed(2);
                const market = (parseFloat(pr.market_price)||0).toFixed(2);
                btn.innerText = sell;
                btn.dataset.selling = sell;
                btn.dataset.market = market;
                btn.addEventListener('click', function(){
                    try { sellInput.value = sell; } catch(e){}
                    try { document.getElementById('pd_selling').innerText = sell; } catch(e){}
                    try { document.getElementById('pd_market').innerText = market; } catch(e){}
                    // remember selected market price for subsequent Add
                    try { window.SELECTED_PRICE_MARKET = market; } catch(e){}
                    dd.remove();
                    // If this dropdown is the main product_selling dropdown and a product is selected, trigger Add
                    try {
                        const panelAdd = document.getElementById('panelAddBtn');
                        if(panelAdd && typeof selectedProduct !== 'undefined' && selectedProduct){
                            try { panelAdd.click(); }
                            catch(e){}
                        }
                    } catch(e){}
                });
                dd.appendChild(btn);
            });

            document.body.appendChild(dd);

            // Update input and preview to the first price
            if(arr.length > 0){
                const firstSell = (parseFloat(arr[0].selling_price)||0).toFixed(2);
                const firstMarket = (parseFloat(arr[0].market_price)||0).toFixed(2);
                sellInput.value = firstSell;
                try { document.getElementById('pd_selling').innerText = firstSell; } catch(e){}
                try { document.getElementById('pd_market').innerText = firstMarket; } catch(e){}
                try { window.SELECTED_PRICE_MARKET = firstMarket; } catch(e){}
            }

            // keyboard navigation inside dropdown when selling input has focus
            const keyNav = function(ev){
                console.log('keyNav called, key:', ev.key);
                const items = dd.querySelectorAll('.list-group-item');
                console.log('items found:', items.length);
                if(!items || !items.length) return;
                if(ev.key === 'ArrowDown' || ev.key === 'Down'){
                    console.log('ArrowDown detected');
                    ev.preventDefault();
                    focused = (focused + 1) % items.length;
                    console.log('new focused:', focused);
                    items.forEach(it => { it.classList.remove('active'); it.style.backgroundColor = ''; it.style.color = ''; });
                    if(items[focused]){ 
                        items[focused].classList.add('active'); 
                        items[focused].style.backgroundColor = '#198754'; 
                        items[focused].style.color = 'white'; 
                    }
                    if(items[focused]) items[focused].scrollIntoView({block:'nearest'});
                    // Update input and preview to selected price
                    const sell = items[focused].dataset.selling;
                    const market = items[focused].dataset.market;
                    sellInput.value = sell;
                    try { document.getElementById('pd_selling').innerText = sell; } catch(e){}
                    try { document.getElementById('pd_market').innerText = market; } catch(e){}
                    try { window.SELECTED_PRICE_MARKET = market; } catch(e){}
                } else if(ev.key === 'ArrowUp' || ev.key === 'Up'){
                    console.log('ArrowUp detected');
                    ev.preventDefault();
                    focused = (focused - 1 + items.length) % items.length;
                    console.log('new focused:', focused);
                    items.forEach(it => { it.classList.remove('active'); it.style.backgroundColor = ''; it.style.color = ''; });
                    if(items[focused]){ 
                        items[focused].classList.add('active'); 
                        items[focused].style.backgroundColor = '#198754'; 
                        items[focused].style.color = 'white'; 
                    }
                    if(items[focused]) items[focused].scrollIntoView({block:'nearest'});
                    // Update input and preview to selected price
                    const sell = items[focused].dataset.selling;
                    const market = items[focused].dataset.market;
                    sellInput.value = sell;
                    try { document.getElementById('pd_selling').innerText = sell; } catch(e){}
                    try { document.getElementById('pd_market').innerText = market; } catch(e){}
                    try { window.SELECTED_PRICE_MARKET = market; } catch(e){}
                } else if(ev.key === 'Enter'){
                    ev.preventDefault();
                    // prefer numeric focused index, otherwise look for any element with active class
                    let idx = focused;
                    if(!(idx >= 0)){
                        const arr = Array.from(items);
                        idx = arr.findIndex(it => it.classList.contains('active'));
                    }
                    if(idx >= 0 && items[idx]){
                        items[idx].click();
                    }
                } else if(ev.key === 'Escape'){
                    dd.remove();
                    try { sellInput.removeEventListener('keydown', keyNav); } catch(e){}
                }
            };

            // remove any previous selling dropdown key handler to avoid duplicate listeners
            try { if(sellInput._sellingKeyNav){ sellInput.removeEventListener('keydown', sellInput._sellingKeyNav); sellInput._sellingKeyNav = null; } } catch(e){}
            // store reference for cleanup and attach directly so dropdown navigation works regardless of global keyboard toggle
            sellInput._sellingKeyNav = keyNav;
            try { sellInput.addEventListener('keydown', keyNav); } catch(e){}

            // keep focus on the selling input so key events are delivered
            try { sellInput.focus(); } catch(e){}

            // close on outside click
            const outsideHandler = function(ev){ if(!dd.contains(ev.target) && ev.target !== sellInput){ dd.remove(); try{ if(sellInput._sellingKeyNav){ try{ sellInput.removeEventListener('keydown', sellInput._sellingKeyNav); }catch(ex){} sellInput._sellingKeyNav = null; } }catch(e){} document.removeEventListener('click', outsideHandler); } };
            setTimeout(() => document.addEventListener('click', outsideHandler));

        } catch(e){ console.warn('openSellingDropdown error', e); }
    }

    function findByBarcode(code){
        return (window.PRODUCTS || []).find(p => String(p.barcode) === String(code) || String(p.code) === String(code) || String(p.id) === String(code));
    }

    // Show a brief notification when saved prices are available
    function showPriceNotification(count){
        try {
            // Create a toast notification
            const toastHtml = `<div class="toast align-items-center text-white bg-info border-0 position-fixed" role="alert" aria-live="assertive" aria-atomic="true" style="top: 20px; right: 20px; z-index: 9999;" data-bs-delay="3000">
                <div class="d-flex">
                    <div class="toast-body">
                        <i class="fas fa-tags me-2"></i>
                        <strong>${count} saved price${count > 1 ? 's' : ''} available!</strong>
                    </div>
                    <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
                </div>
            </div>`;

            // Add to body and show
            document.body.insertAdjacentHTML('beforeend', toastHtml);
            const toastEl = document.body.lastElementChild;
            
            // Vanilla JS: Show toast with animation
            toastEl.classList.add('show');
            
            // Auto-hide after 3 seconds
            setTimeout(function() {
                toastEl.classList.remove('show');
                setTimeout(function() {
                    toastEl.remove();
                }, 300);
            }, 3000);
        } catch(e){
            // Fallback: just log to console if toast fails
            console.log(`${count} saved prices available for this product`);
        }
    }

    // Open selling dropdown for a specific input element and product id (used for row item-selling inputs)
    function openSellingDropdownForInput(inputEl, productId){
        try {
            if(!inputEl) return;
            // remove existing dropdown
            const existing = document.getElementById('selling_price_dropdown'); if(existing) existing.remove();

            let arr = [];
            try {
                if(window.PRICES){
                    arr = window.PRICES[productId] || window.PRICES[String(productId)] || [];
                    if(!arr.length && Array.isArray(window.PRICES)){
                        arr = window.PRICES.filter(pr => String(pr.product_id) === String(productId));
                    }
                }
            } catch(e){ arr = []; }
            if(!arr || !arr.length) return;

            const dd = document.createElement('div');
            dd.id = 'selling_price_dropdown';
            dd.className = 'list-group shadow';
            dd.style.position = 'absolute';
            dd.style.zIndex = 2000;
            const rect = inputEl.getBoundingClientRect();
            dd.style.left = (rect.left + window.scrollX) + 'px';
            dd.style.top = (rect.bottom + window.scrollY) + 'px';
            dd.style.minWidth = (rect.width) + 'px';

            let focused = -1;
            arr.forEach(pr => {
                const btn = document.createElement('button');
                btn.type = 'button';
                btn.className = 'list-group-item list-group-item-action';
                const sell = (parseFloat(pr.selling_price)||0).toFixed(2);
                const market = (parseFloat(pr.market_price)||0).toFixed(2);
                btn.innerText = sell;
                btn.dataset.selling = sell;
                btn.dataset.market = market;
                btn.addEventListener('click', function(){
                    try { inputEl.value = sell; } catch(e){}
                    // also set the market value for this row if present
                    try {
                        const tr = inputEl.closest('tr');
                        if(tr){
                            const mEl = tr.querySelector('.item-market');
                            if(mEl) mEl.value = market;
                        }
                    } catch(e){}
                    dd.remove();
                });
                dd.appendChild(btn);
            });
            document.body.appendChild(dd);

            const keyNav = function(ev){
                const items = dd.querySelectorAll('.list-group-item');
                if(!items || !items.length) return;
                if(ev.key === 'ArrowDown' || ev.key === 'Down'){
                    ev.preventDefault(); focused = Math.min(focused + 1, items.length - 1);
                    items.forEach((it,i)=> it.classList.toggle('active', i === focused));
                    if(items[focused]) items[focused].scrollIntoView({block:'nearest'});
                } else if(ev.key === 'ArrowUp' || ev.key === 'Up'){
                    ev.preventDefault(); focused = Math.max(focused - 1, 0);
                    items.forEach((it,i)=> it.classList.toggle('active', i === focused));
                    if(items[focused]) items[focused].scrollIntoView({block:'nearest'});
                } else if(ev.key === 'Enter'){
                    ev.preventDefault();
                    let idx = focused;
                    if(!(idx >= 0)){
                        const arr = Array.from(items);
                        idx = arr.findIndex(it => it.classList.contains('active'));
                    }
                    if(idx >= 0 && items[idx]) items[idx].click();
                } else if(ev.key === 'Escape'){
                    dd.remove(); try{ inputEl.removeEventListener('keydown', keyNav); }catch(e){}
                }
            };
            // Attach key handler directly so dropdown navigation works even if global shortcuts are disabled
            try { inputEl.addEventListener('keydown', keyNav); } catch(e){}

            const outsideHandler = function(ev){ if(!dd.contains(ev.target) && ev.target !== inputEl){ dd.remove(); try{ inputEl.removeEventListener('keydown', keyNav); }catch(e){} document.removeEventListener('click', outsideHandler); } };
            setTimeout(() => document.addEventListener('click', outsideHandler));

        } catch(e){ console.warn('openSellingDropdownForInput error', e); }
    }

    // Small reusable typable dropdown for inputs (used for customer field and others)
        function createTypableDropdown(inputEl, items, onSelect){
        if(!inputEl) return;
        let dropdown = null;
        let focused = -1;

        function closeDropdown(){
            if(dropdown){ dropdown.remove(); dropdown = null; }
            try { inputEl.removeEventListener('keydown', keyHandler); } catch(e){}
            try { document.removeEventListener('click', outsideHandler); } catch(e){}
        }

        function outsideHandler(ev){ if(dropdown && !dropdown.contains(ev.target) && ev.target !== inputEl){ closeDropdown(); } }

        function keyHandler(ev){
            if(!dropdown) return;
            const itemsEls = dropdown.querySelectorAll('.list-group-item');
                                    if(ev.key === 'ArrowDown' || ev.key === 'Down'){
                ev.preventDefault(); focused = Math.min(focused + 1, itemsEls.length - 1);
                itemsEls.forEach((it,i)=> it.classList.toggle('active', i === focused));
                if(itemsEls[focused]) itemsEls[focused].scrollIntoView({block:'nearest'});
            } else if(ev.key === 'ArrowUp'){
                ev.preventDefault(); focused = Math.max(focused - 1, 0);
                itemsEls.forEach((it,i)=> it.classList.toggle('active', i === focused));
                if(itemsEls[focused]) itemsEls[focused].scrollIntoView({block:'nearest'});
            } else if(ev.key === 'Enter'){
                ev.preventDefault(); if(focused >=0 && itemsEls[focused]) itemsEls[focused].click();
            } else if(ev.key === 'Escape'){
                closeDropdown();
            }
        }

    // helper to escape HTML inside labels
    function escHtml(s){ return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }

    inputEl.addEventListener('input', function(){
            const qRaw = (inputEl.value || '').toString();
            const q = qRaw.toLowerCase();
            const qDigits = qRaw.replace(/\D/g, '');
            if(dropdown) closeDropdown();
            dropdown = document.createElement('div');
            dropdown.className = 'list-group';
            // allow multi-line labels so long "Name — Contact" entries are visible
            dropdown.style.whiteSpace = 'normal';
            dropdown.style.position = 'absolute';
            dropdown.style.zIndex = 9999;
            const rect = inputEl.getBoundingClientRect();
            dropdown.style.left = (rect.left + window.scrollX) + 'px';
            dropdown.style.top = (rect.bottom + window.scrollY) + 'px';
            dropdown.style.minWidth = (rect.width) + 'px';
            // Match by name or contact if available. Normalize digit comparisons so typing
            // phone fragments (with or without leading 0 / country code) matches reliably.
            const results = (items || []).filter(it => {
                const nameMatch = (it.name||'').toString().toLowerCase().includes(q);
                const contactRaw = (it.contact||'').toString();
                const contactLower = contactRaw.toLowerCase();
                const contactDigits = contactRaw.replace(/\D/g, '');

                // Helper to robustly match digit fragments against stored contact digits
                function digitsMatch(contactDigits, queryDigits){
                    if(!queryDigits) return false;
                    if(contactDigits.includes(queryDigits)) return true;
                    // match irrespective of leading 0 vs country code (common Sri Lanka: 0xxxxxx vs 94xxxxxx)
                    const qNoLeadingZero = queryDigits.replace(/^0+/, '');
                    const contactNo94 = contactDigits.replace(/^94/, '');
                    if(qNoLeadingZero && contactDigits.includes(qNoLeadingZero)) return true;
                    if(contactNo94 && contactNo94.includes(queryDigits)) return true;
                    if(contactNo94 && qNoLeadingZero && contactNo94.includes(qNoLeadingZero)) return true;
                    // fall back to endsWith (last digits match)
                    if(contactDigits.endsWith(queryDigits)) return true;
                    if(contactNo94.endsWith(qNoLeadingZero)) return true;
                    return false;
                }

                const contactMatch = contactLower.includes(q) || (qDigits && digitsMatch(contactDigits, qDigits));
                const nicMatch = (it.nic || '').toLowerCase().includes(q);
                return nameMatch || contactMatch || nicMatch;
            }).slice(0,20);
            results.forEach((it, idx) => {
                const btn = document.createElement('button');
                btn.type = 'button';
                btn.className = 'list-group-item list-group-item-action';
                // allow wrapping inside each item so contact numbers aren't clipped
                btn.style.whiteSpace = 'normal';
                // Render name (left) and contact (right) using a flex layout so contact is always visible.
                const safeName = escHtml(it.name || (it.label || ''));
                const safeContact = escHtml(it.contact || '');
                // Render a plain-text fallback "Name | Contact | NIC" to avoid CSS hiding the contact
                const textLabel = (it.name || '') + (it.contact ? (' | ' + it.contact) : '') + (it.nic ? (' | ' + it.nic) : '');
                try {
                    btn.textContent = textLabel;
                } catch(e){
                    // fallback to innerHTML if textContent isn't supported (very old browsers)
                    btn.innerHTML = escHtml(textLabel);
                }
                btn.addEventListener('click', function(){
                    try { onSelect && onSelect(it); } catch(e){}
                    // show both name and contact in the visible input for clarity
                        try {
                            // Show only the customer name in the visible input
                            inputEl.value = it.name || '';
                            const contactDisplay = document.getElementById('customer_contact_display');
                            if(contactDisplay) contactDisplay.innerText = (it.contact || '') + (it.nic ? (' | ' + it.nic) : '');
                        } catch(e){
                            inputEl.value = it.name || '';
                        }
                    closeDropdown();
                });
                dropdown.appendChild(btn);
            });
            if(!results.length){ const empty = document.createElement('div'); empty.className='list-group-item text-muted'; empty.innerText='No matches'; dropdown.appendChild(empty); }
            document.body.appendChild(dropdown);
            if(results.length > 0){
                focused = 0;
                const itemsEls = dropdown.querySelectorAll('.list-group-item');
                itemsEls.forEach((it,i)=> it.classList.toggle('active', i === focused));
            } else {
                focused = -1;
            }
            setTimeout(()=> document.addEventListener('click', outsideHandler));
            attachKeydown(inputEl, keyHandler);
        });

        // close on blur after short delay to allow click
        inputEl.addEventListener('blur', function(){ setTimeout(closeDropdown, 150); });
    }

    function addItem(product, qty = 1, sellingOverride = null, isExistingItem = false){
        // Check if there's enough stock before adding (skip for existing invoice items)
        if(!isExistingItem){
            try {
                const currentMode = document.querySelector('input[name="invoice_mode"]:checked')?.value || 'cash';
                // If preorder, skip stock checks
                if (currentMode !== 'preorder') {
                    const prodList = window.PRODUCTS || [];
                    const pidx = prodList.findIndex(pp => String(pp.id) === String(product.id));
                    if(pidx >= 0){
                        const pObj = prodList[pidx];
                        const availableQty = parseFloat(pObj.qty || 0) || 0;
                        if(qty > availableQty){
                            // Show error message and prevent adding
                            alert(`Insufficient stock! Available quantity: ${availableQty}, Requested: ${qty}`);
                            return false;
                        }
                    }
                }
            } catch(e){ /* ignore errors and proceed */ }
        }

        // optional marketOverride passed when user selected a saved price before adding
        let marketOverride = null;
        if(arguments.length > 3){ marketOverride = arguments[3]; }
        const tbody = document.querySelector('#itemsTable tbody');
        const row = document.createElement('tr');
    // lock selling in the row if product.is_active indicates it's protected
    const sellingLocked = (typeof product.is_active !== 'undefined') && (product.is_active === 1 || product.is_active === '1' || product.is_active === true);
            const sellingVal = (typeof sellingOverride !== 'undefined' && sellingOverride !== null) ? parseFloat(sellingOverride) : parseFloat(product.selling || 0);
            const marketVal = (marketOverride !== null) ? parseFloat(marketOverride) : ((typeof product.market !== 'undefined') ? parseFloat(product.market) : sellingVal);

            // per-item cost derived from product.total_cost / product.qty (if product.qty > 0)
            const perItemCost = (typeof product.cost !== 'undefined' && parseFloat(product.cost) && parseFloat(product.qty)) ? (parseFloat(product.cost) / parseFloat(product.qty)) : (parseFloat(product.cost) || 0);

            // Prevent adding when selling price is lower than the allowed minimum for new items
            // Minimum allowed = per item cost + 10% (i.e. cost * 1.1)
            if (!isExistingItem) {
                try {
                    const minAllowed = parseFloat(perItemCost || 0) * 1.1;
                    if (!isNaN(parseFloat(sellingVal)) && !isNaN(parseFloat(perItemCost)) && parseFloat(sellingVal) < minAllowed) {
                        alert('Selling price must be at least 10% above Per Item Cost. Minimum allowed: Rs. ' + minAllowed.toFixed(2));
                        return false;
                    }
                } catch(e){ /* ignore */ }
            }
            // Do not auto-calculate discount from market - selling. Use selling price for totals.
            const sellingTotal = sellingVal * qty;
            const total = sellingTotal; // total payable is selling * qty
            const discount = 0; // default discount; user may enter manual discount per row
        // Build row HTML and include market cell only when the page flag allows it
        let marketCellHtml = '';
        try {
            if (window.SHOW_MARKET_IN_ITEMS !== false) {
                marketCellHtml = `<td><input class="form-control form-control-sm item-market" value="${marketVal.toFixed(2)}" style="width:100px"></td>`;
            }
        } catch(e){ /* ignore */ }

        row.innerHTML = `
            <td data-id="${product.id}">${product.name}</td>
            <td class="item-code">${product.code || ''}</td>
            <td><input class="form-control form-control-sm item-qty" value="${qty}" style="width:80px"></td>
            <td><input class="form-control form-control-sm item-warranty" value="0" style="width:80px"></td>
                <td><input class="form-control form-control-sm item-cost" value="${perItemCost.toFixed(2)}" style="width:100px"></td>
                ${marketCellHtml}
            <td><input class="form-control form-control-sm item-selling ${sellingLocked ? 'bg-light' : ''}" value="${sellingVal.toFixed(2)}" style="width:100px" ${sellingLocked ? 'readonly' : ''}></td>
            <td class="item-selling-total">${sellingTotal.toFixed(2)}</td>
            <td><input class="form-control form-control-sm item-discount" value="${discount.toFixed(2)}" style="width:100px"></td>
            <td class="item-total">${total.toFixed(2)}</td>
            <td><button class="btn btn-sm btn-danger btn-remove">Remove</button></td>
        `;
        // store metadata on the row for inventory adjustments
        row.dataset.productId = product.id;
        row.dataset.addedQty = qty;
    // Track last valid selling value so edits can be validated/reverted
    try { row.dataset.prevSelling = parseFloat(sellingVal).toFixed(2); } catch(e){}
        tbody.appendChild(row);
        // If we're on the Create Invoice page, make all per-row inputs readonly
        // On Edit page, make readonly only for inactive products (is_active = 0)
        try {
            const saveBtn = document.getElementById('saveInvoice');
            const btnText = (saveBtn && (saveBtn.innerText || saveBtn.textContent || '') ) || '';
            const isCreatePage = /save invoice/i.test(btnText);
            const isEditPage = /update invoice/i.test(btnText);
            const shouldReadonly = isCreatePage || (isEditPage && (product.is_active == 0 || product.is_active == '0' || product.is_active === false));
            if(shouldReadonly){
                ['.item-qty', '.item-market', '.item-selling', '.item-discount'].forEach(sel => {
                    const el = row.querySelector(sel);
                    if(el) el.setAttribute('readonly', 'readonly');
                });
            }
        } catch(e){ /* ignore */ }
        // decrement inventory in the PRODUCTS array (client-side preview)
        try {
            const prodList = window.PRODUCTS || [];
            const pidx = prodList.findIndex(pp => String(pp.id) === String(product.id));
            if(pidx >= 0){
                const pObj = prodList[pidx];
                const curQty = parseFloat(pObj.qty || 0) || 0;
                const curCost = parseFloat(pObj.cost || 0) || 0;
                const per = parseFloat(perItemCost) || 0;
                pObj.qty = Math.max(0, curQty - qty);
                // reduce total cost by per-item*qty, floor at 0
                pObj.cost = Math.max(0, curCost - (per * qty));
                // if currently previewing this product, refresh the right panel
                try { if(window.selectedProduct && String(window.selectedProduct.id) === String(pObj.id)){ showProductDetails(pObj); } } catch(e){}
            }
        } catch(e){ console.warn('Error adjusting PRODUCTS after addItem', e); }

        attachRowEvents(row);
        recalc();
    }

    function attachRowEvents(row){
        try {
            // Attach handlers for inputs; qty needs special handling to adjust client-side inventory
            const qtyEl = row.querySelector('.item-qty');
            const costEl = row.querySelector('.item-cost');
            const marketEl = row.querySelector('.item-market');
            const sellingEl = row.querySelector('.item-selling');
            const discountEl = row.querySelector('.item-discount');

            // Generic recalc for non-qty fields
            [costEl, marketEl, sellingEl, discountEl].forEach(el => {
                try { if(el) el.addEventListener('input', recalc); } catch(e){}
            });

            // Qty handler: update row.dataset.addedQty and adjust PRODUCTS inventory delta
            if(qtyEl){
                qtyEl.addEventListener('input', function(){
                    try {
                        const now = parseFloat(this.value) || 0;

                        // Check if new quantity exceeds available stock
                        const pid = row.dataset.productId;
                        const prodList = window.PRODUCTS || [];
                        const idx = prodList.findIndex(pp => String(pp.id) === String(pid));
                        if(idx >= 0){
                            const pObj = prodList[idx];
                            const availableQty = parseFloat(pObj.qty || 0) || 0;
                            const prev = parseFloat(row.dataset.addedQty || 0) || 0;

                            // Calculate total quantity that would be used (existing rows + this change)
                            let totalUsedQty = 0;
                            document.querySelectorAll('#itemsTable tbody tr').forEach(tr => {
                                if(tr.dataset.productId === pid && tr !== row){
                                    const existingQty = parseFloat(tr.querySelector('.item-qty').value) || 0;
                                    totalUsedQty += existingQty;
                                }
                            });
                            totalUsedQty += now;

                            try {
                                const currentMode = document.querySelector('input[name="invoice_mode"]:checked')?.value || 'cash';
                                if (currentMode !== 'preorder') {
                                    if(totalUsedQty > (availableQty + prev)){
                                        alert(`Insufficient stock! Available quantity: ${availableQty + prev}, Requested total: ${totalUsedQty}`);
                                        this.value = prev; // Revert to previous value
                                        return;
                                    }
                                }
                            } catch(e){ /* ignore */ }
                        }

                        const prev = parseFloat(row.dataset.addedQty || 0) || 0;
                        const delta = now - prev; // positive means increase in row qty (so reduce inventory further)
                        row.dataset.addedQty = now;
                        if(delta !== 0){
                            try {
                                const prodList = window.PRODUCTS || [];
                                const idx = prodList.findIndex(pp => String(pp.id) === String(pid));
                                if(idx >= 0){
                                    const pObj = prodList[idx];
                                    const curQty = parseFloat(pObj.qty || 0) || 0;
                                    const curCost = parseFloat(pObj.cost || 0) || 0;
                                    const per = parseFloat(costEl?.value || 0) || 0;
                                    // subtract delta from inventory qty (if delta positive) or add back (if negative)
                                    pObj.qty = Math.max(0, curQty - delta);
                                    // adjust total cost opposite to inventory change
                                    pObj.cost = Math.max(0, curCost - (per * delta));
                                    if(window.selectedProduct && String(window.selectedProduct.id) === String(pObj.id)){
                                        showProductDetails(pObj);
                                    }
                                }
                            } catch(e){ console.warn('Error adjusting PRODUCTS on qty change', e); }
                        }
                    } catch(e){ console.warn('qty input handler error', e); }
                    recalc();
                });
            }

            // Attach selling-dropdown behavior for per-row selling inputs (edit mode)
            try {
                const sellInput = sellingEl;
                const idCell = row.querySelector('td[data-id]');
                const productId = idCell ? idCell.dataset.id : null;
                if(sellInput && productId){
                    // Prevent arrow keys from changing the numeric value in per-row selling inputs
                    sellInput.addEventListener('keydown', function(ev){
                        if(ev.key === 'ArrowDown' || ev.key === 'ArrowUp' || ev.key === 'Down' || ev.key === 'Up'){
                            try { ev.preventDefault(); } catch(e){}
                        }
                    });
                    // Validate selling input against market for both create and edit rows
                    sellInput.addEventListener('input', function(ev){
                        try {
                            const newVal = parseFloat(this.value) || 0;
                            // Resolve market value: prefer per-row market input, otherwise product master data
                            let mVal = null;
                            try {
                                const mEl = row.querySelector('.item-market');
                                if(mEl) mVal = parseFloat(mEl.value) || 0;
                            } catch(e){}
                            if(mVal === null || typeof mVal === 'undefined'){
                                try {
                                    const prod = (window.PRODUCTS || []).find(p => String(p.id) === String(productId));
                                    if(prod) mVal = parseFloat(prod.market || prod.wholesale || prod.selling || 0) || 0;
                                } catch(e) { mVal = 0; }
                            }
                            // Enforce minimum allowed selling relative to per-item cost (10% markup)
                            try {
                                const perItemCost = parseFloat(row.querySelector('.item-cost')?.value || 0) || 0;
                                const minAllowed = parseFloat(perItemCost) * 1.1;
                                if(!isNaN(newVal) && !isNaN(minAllowed) && newVal < minAllowed){
                                    // Revert to previous valid selling value
                                    try { const prev = parseFloat(row.dataset.prevSelling) || 0; this.value = prev.toFixed(2); } catch(e){}
                                    alert('Selling price must be at least 10% above Per Item Cost. Minimum allowed: Rs. ' + minAllowed.toFixed(2));
                                    recalc();
                                    return;
                                }
                            } catch(e){ /* ignore cost-based check errors */ }

                            // Validate selling input against market for both create and edit rows (keep existing behavior)
                            if(!isNaN(newVal) && !isNaN(mVal) && parseFloat(newVal) < parseFloat(mVal)){
                                // Revert to previous valid selling value
                                try {
                                    const prev = parseFloat(row.dataset.prevSelling) || 0;
                                    this.value = prev.toFixed(2);
                                } catch(e){ }
                                alert('Selling price cannot be lower than Market price.');
                                recalc();
                                return;
                            }

                            // update prevSelling on valid input
                            try { row.dataset.prevSelling = parseFloat(this.value || 0).toFixed(2); } catch(e){}
                        } catch(e){ }
                    });
                }
            } catch(e){ console.warn('attachRowEvents selling binding error', e); }

            // Remove button: restore inventory then remove row
            const removeBtn = row.querySelector('.btn-remove');
            if(removeBtn){
                removeBtn.addEventListener('click', function(){
                    try {
                        const pid = row.dataset.productId;
                        const returnedQty = parseFloat(row.dataset.addedQty || (row.querySelector('.item-qty')?.value || 0)) || 0;
                        const per = parseFloat(row.querySelector('.item-cost')?.value || 0) || 0;
                        if(pid){
                            const prodList = window.PRODUCTS || [];
                            const idx = prodList.findIndex(pp => String(pp.id) === String(pid));
                            if(idx >= 0){
                                const pObj = prodList[idx];
                                        try { const codeCell = tr.querySelector('.item-code'); if(codeCell) codeCell.innerText = prod.code || (it.code || ''); } catch(e){}
                                        try { const sellingEl = tr.querySelector('.item-selling'); if(sellingEl) tr.dataset.prevSelling = parseFloat(sellingEl.value || sellingEl.getAttribute('value') || 0).toFixed(2); } catch(e){}
                                pObj.cost = (parseFloat(pObj.cost || 0) || 0) + (per * returnedQty);
                                if(window.selectedProduct && String(window.selectedProduct.id) === String(pObj.id)){
                                    showProductDetails(pObj);
                                }
                            }
                        }
                    } catch(e){ console.warn('Error restoring PRODUCTS on remove', e); }
                    try { row.remove(); } catch(e){}
                    recalc();
                });
            }
        } catch(e){ console.warn('attachRowEvents general error', e); }
    }

    // Track payments
    let payments = [];

    function updatePaymentsDisplay(){
        const listEl = document.getElementById('payments_list');
        const cashPaidEl = document.getElementById('payment_cashpaid');
        const balanceEl = document.getElementById('payment_balance');
        const netTotalEl = document.getElementById('payment_nettotal');
        if(!listEl) return;

        if(payments.length === 0){
            listEl.innerHTML = '<div class="text-muted small">No payments yet</div>';
        } else {
            let html = '';
            payments.forEach((p, i) => {
                html += `<div class="d-flex justify-content-between align-items-center mb-1">
                    <small>${p.amount.toFixed(2)}</small>
                    <button type="button" class="btn btn-sm btn-danger btn-remove-payment" data-index="${i}">×</button>
                </div>`;
            });
            listEl.innerHTML = html;
            // Add remove events
            listEl.querySelectorAll('.btn-remove-payment').forEach(btn => {
                btn.addEventListener('click', function(){
                    const idx = parseInt(this.dataset.index);
                    payments.splice(idx, 1);
                    updatePaymentsDisplay();
                    recalc();
                });
            });
        }

        // Do not override user's cash input here. Instead compute totals including
        // cash, card and any ad-hoc payments in the payments array.
        const paymentsSum = payments.reduce((sum, p) => sum + p.amount, 0);
        const cashVal = parseFloat(cashPaidEl ? (cashPaidEl.value || 0) : 0) || 0;
        const cardVal = parseFloat((document.getElementById('card_amount') || {}).value || 0) || 0;

        // Update balance (payment_balance hidden input / field)
        const netTotal = parseFloat(netTotalEl ? netTotalEl.value : 0) || 0;
    const totalPaid = cashVal + cardVal + paymentsSum;
    const remaining = Math.max(0, netTotal - totalPaid);
    if(balanceEl) balanceEl.value = remaining.toFixed(2);
    }

    function recalc(){
        let subtotal = 0;
        let discount = 0;
        let netTotal = 0;

        // Calculate subtotal and discount from items
        // Use selling price as the payable line price. Discount is read from the user-entered
        // per-row discount input rather than auto-calculated from market - selling.
        // Exclude the customer balance row from calculations
        document.querySelectorAll('#itemsTable tbody tr').forEach(tr => {
            // Skip the customer balance info row
            if (tr.id === 'customerBalanceRow') return;
            
            const qtyEl = tr.querySelector('.item-qty');
            const sellingEl = tr.querySelector('.item-selling');
            
            // Skip rows that don't have item fields (safety check)
            if (!qtyEl || !sellingEl) return;
            
            const qty = parseFloat(qtyEl.value) || 0;
            const selling = parseFloat(sellingEl.value) || 0;
            // Market may be present for display but totals are based on selling
            const marketEl = tr.querySelector('.item-market');
            const market = marketEl ? (parseFloat(marketEl.value) || selling) : selling;
            // per-item cost (from per-row input)
            const perItem = parseFloat(tr.querySelector('.item-cost')?.value || 0) || 0;
            // Read user-entered discount for the row (manual input)
            const discountEl = tr.querySelector('.item-discount');
            const itemDiscount = parseFloat(discountEl?.value || 0) || 0;

            // Line total is selling * qty (what customer pays)
            const line = selling * qty;
            const totalEl = tr.querySelector('.item-total');
            if (totalEl) totalEl.innerText = line.toFixed(2);

            // Update selling total display
            const sellingTotal = selling * qty;
            const sellingTotalEl = tr.querySelector('.item-selling-total');
            if(sellingTotalEl) sellingTotalEl.innerText = sellingTotal.toFixed(2);

            subtotal += line;
            discount += itemDiscount;
        });

        // (Cost total column removed) no aggregate cost update here

        // Net total = subtotal - discount
        netTotal = subtotal - discount;

        // Update fields (skip payment fields that don't exist in invoice create)
        const subtotalEl = document.getElementById('payment_subtotal');
        if(subtotalEl) subtotalEl.value = subtotal.toFixed(2);
        const discountEl = document.getElementById('payment_discount');
        if(discountEl) discountEl.value = discount.toFixed(2);
        const nettotalEl = document.getElementById('payment_nettotal');
        if(nettotalEl) nettotalEl.value = netTotal.toFixed(2);

        // Update summary section with payment values
        const summarySubtotalEl = document.getElementById('summary_subtotal');
        if(summarySubtotalEl) summarySubtotalEl.innerText = subtotal.toFixed(2);
        const summaryDiscountEl = document.getElementById('summary_discount');
        if(summaryDiscountEl) summaryDiscountEl.innerText = discount.toFixed(2);
        const summaryNettotalEl = document.getElementById('summary_nettotal');
        if(summaryNettotalEl) summaryNettotalEl.innerText = netTotal.toFixed(2);
        const summaryBalanceEl = document.getElementById('summary_balance');
        if(summaryBalanceEl) {
            // Include cash, card and any other payments in balance computation
            const cashVal = parseFloat((document.getElementById('payment_cashpaid') || {}).value || 0) || 0;
            const cardVal = parseFloat((document.getElementById('card_amount') || {}).value || 0) || 0;
                const paymentsSum = payments.reduce((sum, p) => sum + p.amount, 0);
                const totalPaid = cashVal + cardVal + paymentsSum;
                const remaining = Math.max(0, netTotal - totalPaid);
                summaryBalanceEl.innerText = remaining.toFixed(2);
        }

        // Update Num Of Items (total quantity of all products)
        const numOfItemsEl = document.getElementById('NumOfItems');
        if(numOfItemsEl) {
            let totalQty = 0;
            document.querySelectorAll('#itemsTable tbody tr').forEach(tr => {
                // Skip the customer balance info row
                if (tr.id === 'customerBalanceRow') return;
                
                const qtyEl = tr.querySelector('.item-qty');
                if (!qtyEl) return; // Skip rows without qty field
                
                const qty = parseFloat(qtyEl.value) || 0;
                totalQty += qty;
            });
            numOfItemsEl.innerText = totalQty.toFixed(2);
        }

        // Update payments display (cash paid and balance)
        updatePaymentsDisplay();
    }

    document.addEventListener('DOMContentLoaded', function(){
        // Debug: print available prices map (helps diagnose create vs edit differences)
        try { console.debug('INVOICE JS: window.PRICES ->', window.PRICES); } catch(e){}
        // Focus product search input on page load
        try {
            const psearchEl = document.getElementById('product_search');
            if(psearchEl){ psearchEl.focus(); }
        } catch(e){}
        // Event for payment discount
        try {
            const discountEl = document.getElementById('payment_discount');
            if(discountEl) discountEl.addEventListener('input', recalc);
        } catch(e){}
        // Event for cash paid input to update balance (include card + other payments)
        try {
            const cashPaidEl = document.getElementById('payment_cashpaid');
            if(cashPaidEl) cashPaidEl.addEventListener('input', function(){
                // Update balance when cash paid changes (include card amount and ad-hoc payments)
                const netTotalEl = document.getElementById('summary_nettotal');
                const summaryBalanceEl = document.getElementById('summary_balance');

                const netTotal = parseFloat(netTotalEl ? netTotalEl.innerText : 0) || 0;
                const cashPaid = parseFloat(this.value || 0) || 0;
                const cardPaid = parseFloat((document.getElementById('card_amount') || {}).value || 0) || 0;
                const paymentsSum = payments.reduce((s, p) => s + p.amount, 0);
                const remaining = Math.max(0, netTotal - (cashPaid + cardPaid + paymentsSum));

                if(summaryBalanceEl) summaryBalanceEl.innerText = remaining.toFixed(2);
            });
        } catch(e){}

        // Event for card amount input to update balance (so card changes reflect immediately)
        try {
            const cardEl = document.getElementById('card_amount');
            if(cardEl) cardEl.addEventListener('input', function(){
                const netTotalEl = document.getElementById('summary_nettotal');
                const summaryBalanceEl = document.getElementById('summary_balance');
                const netTotal = parseFloat(netTotalEl ? netTotalEl.innerText : 0) || 0;
                const cardPaid = parseFloat(this.value || 0) || 0;
                const cashPaid = parseFloat((document.getElementById('payment_cashpaid') || {}).value || 0) || 0;
                const paymentsSum = payments.reduce((s, p) => s + p.amount, 0);
                const remaining = Math.max(0, netTotal - (cashPaid + cardPaid + paymentsSum));
                if(summaryBalanceEl) summaryBalanceEl.innerText = remaining.toFixed(2);
            });
        } catch(e){}
        // Event for add payment
        try {
            const addPaymentBtn = document.getElementById('addPaymentBtn');
            const paymentAmountEl = document.getElementById('payment_amount');
            if(addPaymentBtn && paymentAmountEl){
                addPaymentBtn.addEventListener('click', function(){
                    const amount = parseFloat(paymentAmountEl.value) || 0;
                    if(amount > 0){
                        payments.push({ amount: amount });
                        paymentAmountEl.value = '';
                        updatePaymentsDisplay();
                        recalc();
                    }
                });
            }
        } catch(e){}
        // Prevent Enter key from submitting the invoice form unintentionally on create/edit pages.
        // If user actually wants to submit, they should click the Save button.
        try {
            const invoiceForm = document.getElementById('invoiceForm');
            if(invoiceForm){
                invoiceForm.addEventListener('keydown', function(ev){
                    if(ev.key === 'Enter'){
                        // allow Enter inside textareas
                        if(ev.target && ev.target.tagName && ev.target.tagName.toLowerCase() === 'textarea') return;
                        // allow Enter when target is a button (so buttons can be activated)
                        if(ev.target && ev.target.tagName && ev.target.tagName.toLowerCase() === 'button') return;
                        // prevent default submission for inputs
                        ev.preventDefault();
                        ev.stopPropagation();
                        return false;
                    }
                });
            }
        } catch(e){ console.warn('Error attaching prevent-Enter handler', e); }
        // Barcode input removed: barcode scanning still works via product_search or by typing barcode into the search box

        // product search simple filter
        const psearch = document.getElementById('product_search');
        let dropdown;

        // Global F1 shortcut: focus product search input on F1 press (override browser help)
        try {
            document.addEventListener('keydown', function(ev){
                // Some browsers use ev.key === 'F1', older may use keyCode 112
                if(ev.key === 'F1' || ev.keyCode === 112){
                    try { ev.preventDefault(); } catch(e){}
                    try {
                        const el = document.getElementById('product_search');
                        if(el){ el.focus(); try{ el.select(); }catch(e){} }
                    } catch(e){}
                }
                // F2 shortcut: remove last added item from invoice table
                else if(ev.key === 'F2' || ev.keyCode === 113){
                    try { ev.preventDefault(); } catch(e){}
                    try {
                        const tableBody = document.querySelector('#itemsTable tbody');
                        if(tableBody){
                            const rows = tableBody.querySelectorAll('tr');
                            if(rows.length > 0){
                                // Remove the last row
                                rows[rows.length - 1].remove();
                                // Trigger recalculation if function exists
                                try { if(typeof recalc === 'function') recalc(); } catch(e){}
                                // Show feedback
                                console.log('Last item removed from invoice');
                            }
                        }
                    } catch(e){ console.warn('F2 shortcut failed', e); }
                }
                // F5 shortcut: focus Cash Paid input field
                else if(ev.key === 'F5' || ev.keyCode === 116){
                    try { ev.preventDefault(); } catch(e){}
                    try {
                        const el = document.getElementById('payment_cashpaid');
                        if(el){ el.focus(); try{ el.select(); }catch(e){} }
                    } catch(e){ console.warn('F5 shortcut failed', e); }
                }
            });
        } catch(e){ console.warn('Keyboard shortcuts attach failed', e); }

        // currently previewed/selected product for the right-side panel and Add buttons
        // defined in this outer scope so other handlers (inline Add / panel Add) can access it
        let selectedProduct = null;
        function showProductDetails(p){
            selectedProduct = p;
            try { window.selectedProduct = p; } catch(e){}
            console.log('Product details:', p); // Debug log to see branch_name
            document.getElementById('pd_name').innerText = p.name || '-';
            document.getElementById('pd_code').innerText = p.code || '-';
            document.getElementById('pd_barcode').innerText = p.barcode || '-';
            // Resolve branch name and qty: prefer explicit p.branch_name/p.qty, otherwise prefer stock for invoice branch,
            // then try matching qty, finally fall back to first stock row.
            try {
                let branchName = (p.branch_name && p.branch_name !== 'null') ? p.branch_name : null;
                let displayQty = (typeof p.qty !== 'undefined') ? parseFloat(p.qty) : null;
                let found = null;
                if (window.PRODUCT_STOCKS && window.PRODUCT_STOCKS[p.id]) {
                    const stocks = window.PRODUCT_STOCKS[p.id] || [];
                    // 1) prefer stock that matches the invoice branch id (if provided)
                    try {
                        if (typeof window.INVOICE_BRANCH_ID !== 'undefined' && window.INVOICE_BRANCH_ID !== null) {
                            found = stocks.find(s => String(s.branch_id) === String(window.INVOICE_BRANCH_ID));
                        }
                    } catch(e){}
                    // 2) if not found, try matching the product's qty (useful for edit rows)
                    if (!found && displayQty !== null) {
                        found = stocks.find(s => Math.abs((parseFloat(s.qty)||0) - displayQty) < 0.0001);
                    }
                    // 3) fallback to first stock row
                    if (!found) found = stocks[0] || null;
                }

                if (found) {
                    // Prefer the authoritative stock row for branch name and quantity.
                    // Use found.branch_name first, then existing branchName as fallback.
                    branchName = found.branch_name || branchName || (found.branch_id ? String(found.branch_id) : null);
                    // Always prefer the stock row's qty when available (avoids stale p.qty values).
                    displayQty = (typeof found.qty !== 'undefined' && found.qty !== null) ? parseFloat(found.qty) : displayQty;
                }

                document.getElementById('pd_branch').innerText = branchName || '-';
                document.getElementById('pd_qty').innerText = (displayQty !== null) ? displayQty : '-';
            } catch(e){
                try { document.getElementById('pd_branch').innerText = (p.branch_name && p.branch_name !== 'null') ? p.branch_name : '-'; } catch(ex){}
                try { document.getElementById('pd_qty').innerText = (typeof p.qty !== 'undefined') ? p.qty : '-'; } catch(ex){}
            }
            
            // Calculate and display per-item cost (total_cost / qty) in pd_market
            try {
                const rawCost = (typeof p.cost !== 'undefined') ? parseFloat(p.cost) : null;
                const rawQty = (typeof p.qty !== 'undefined') ? parseFloat(p.qty) : null;
                let perItemCost = null;
                if(rawCost !== null && rawQty && rawQty > 0){
                    perItemCost = (rawCost / rawQty).toFixed(2);
                } else if(rawCost !== null){
                    perItemCost = rawCost.toFixed(2);
                }
                document.getElementById('pd_market').innerText = (perItemCost !== null) ? perItemCost : '-';
            } catch(e){
                try { document.getElementById('pd_market').innerText = '-'; } catch(ex){}
            }
            
            document.getElementById('pd_wholesale').innerText = (typeof p.wholesale !== 'undefined') ? parseFloat(p.wholesale).toFixed(2) : '-';
            // Show per-item cost in the preview when possible (product.cost is total_cost)
            try {
                const rawCost = (typeof p.cost !== 'undefined') ? parseFloat(p.cost) : null;
                const rawQty = (typeof p.qty !== 'undefined') ? parseFloat(p.qty) : null;
                let displayCost = null;
                if(rawCost !== null && rawQty && rawQty > 0){
                    displayCost = (rawCost / rawQty).toFixed(2);
                } else if(rawCost !== null){
                    displayCost = rawCost.toFixed(2);
                }
                document.getElementById('pd_cost').innerText = (displayCost !== null) ? displayCost : '-';
            } catch(e){
                try { document.getElementById('pd_cost').innerText = (typeof p.cost !== 'undefined') ? parseFloat(p.cost).toFixed(2) : '-'; } catch(ex){}
            }
            document.getElementById('pd_selling').innerText = (typeof p.selling !== 'undefined') ? parseFloat(p.selling).toFixed(2) : '-';
            // Warranty days (show if provided)
            try { document.getElementById('pd_warranty').innerText = (typeof p.warranty_days !== 'undefined') ? (parseInt(p.warranty_days) || 0) : 0; } catch(e){}
            // Compute and display minimum allowed selling price (per-item cost * 1.3)
            try {
                const rawCost2 = (typeof p.cost !== 'undefined') ? parseFloat(p.cost) : null;
                const rawQty2 = (typeof p.qty !== 'undefined') ? parseFloat(p.qty) : null;
                let per = null;
                if(rawCost2 !== null && rawQty2 && rawQty2 > 0){
                    per = (rawCost2 / rawQty2);
                } else if(rawCost2 !== null){
                    per = rawCost2;
                }
                if(per !== null){
                    const minAllowed = parseFloat(per) * 1.1;
                    const el = document.getElementById('pd_min_selling');
                    if(el) el.innerText = parseFloat(minAllowed || 0).toFixed(2);
                } else {
                    const el = document.getElementById('pd_min_selling'); if(el) el.innerText = '-';
                }
            } catch(e){ try{ const el = document.getElementById('pd_min_selling'); if(el) el.innerText = '-'; }catch(ex){} }
            // show any prices from the PRICES map (product_id => [price objects])
            try {
                const priceListEl = document.getElementById('pd_price_list');
                if(priceListEl){
                    // Robustly resolve saved prices for this product. The server normally injects an object
                    // keyed by product_id, but depending on encoding it might be an array. Handle both.
                    let arr = [];
                    try {
                        if (window.PRICES) {
                            // try numeric and string keys
                            arr = window.PRICES[p.id] || window.PRICES[String(p.id)] || [];
                            // if window.PRICES is a flat array of price objects, filter them
                            if (!arr.length && Array.isArray(window.PRICES)) {
                                arr = window.PRICES.filter(pr => String(pr.product_id) === String(p.id));
                            }
                        }
                    } catch(e){ arr = []; }
                    try { console.debug('showProductDetails -> product id:', p.id, 'prices found:', arr.length, arr); } catch(e){}
                    if(!arr.length){
                        priceListEl.innerHTML = '<div class="text-muted small">No saved prices</div>';
                        // remove any existing selling dropdown
                        const oldDd = document.getElementById('selling_price_dropdown'); if(oldDd) oldDd.remove();
                    } else {
                        // Also show a brief toast notification
                        showPriceNotification(arr.length);

                        // Build enhanced price cards/buttons for better interaction
                        let pricesHtml = '<div class="d-grid gap-2">';
                        arr.forEach((pr, index) => {
                            const sell = (parseFloat(pr.selling_price)||0).toFixed(2);
                            const market = (parseFloat(pr.market_price)||0).toFixed(2);
                            const remark = (pr.remark||'').replace(/</g,'&lt;').replace(/>/g,'&gt;').slice(0,50);
                            const isSelected = (parseFloat(p.selling||0).toFixed(2) === sell);

                            pricesHtml += `<div class="price-card btn ${isSelected ? 'btn-success' : 'btn-outline-primary'} btn-sm text-start p-2 ${index === 0 ? 'highlight-card' : ''}" data-price-id="${pr.id}" data-selling="${sell}" data-market="${market}" style="font-size: 0.8rem;">
                                <div class="d-flex justify-content-between align-items-center">
                                    <div>
                                        <strong class="text-primary">Rs. ${sell}</strong>
                                        ${remark ? `<br><small class="text-muted">${remark}</small>` : ''}
                                    </div>
                                    <div class="text-end">
                                        <small class="text-muted d-block">Market: Rs. ${market}</small>
                                        <small class="text-muted d-block">Wholesale: Rs. ${wholesale}</small>
                                    </div>
                                </div>
                            </div>`;
                        });
                        pricesHtml += '</div>';

                        priceListEl.innerHTML = pricesHtml;

                        // Add blinking animation to draw attention
                        setTimeout(() => {
                            const priceCards = priceListEl.querySelectorAll('.price-card');
                            priceCards.forEach((card, index) => {
                                // Add attention-grabbing animation with delay
                                setTimeout(() => {
                                    card.classList.add('attention-flash');
                                    // Add a gentle shake effect
                                    setTimeout(() => {
                                        card.classList.add('shake-animation');
                                    }, 300);
                                    setTimeout(() => {
                                        card.classList.remove('attention-flash');
                                        card.classList.remove('shake-animation');
                                    }, 2000); // Remove animation after 2 seconds
                                }, index * 200); // Stagger the animations
                            });
                        }, 500); // Start animation after cards are rendered

                        // Attach click handlers to price cards
                        try {
                            const priceCards = priceListEl.querySelectorAll('.price-card');
                            priceCards.forEach(card => {
                                card.addEventListener('click', function(){
                                    // remove active state from others
                                    priceCards.forEach(c => c.classList.remove('btn-success'));
                                    priceCards.forEach(c => c.classList.add('btn-outline-primary'));
                                    // add active state to clicked card
                                    this.classList.remove('btn-outline-primary');
                                    this.classList.add('btn-success');

                                    const s = this.dataset.selling;
                                    const m = this.dataset.market;
                                    const w = this.dataset.wholesale;
                                    // set the selling input and display values
                                    try { document.getElementById('product_selling').value = parseFloat(s).toFixed(2); } catch(e){}
                                    try { document.getElementById('pd_selling').innerText = parseFloat(s).toFixed(2); } catch(e){}
                                    try { document.getElementById('pd_market').innerText = parseFloat(m).toFixed(2); } catch(e){}
                                    try { document.getElementById('pd_wholesale').innerText = parseFloat(w).toFixed(2); } catch(e){}

                                    // Show success feedback
                                    const originalText = this.innerHTML;
                                    this.innerHTML = '<strong>✓ Applied!</strong>';
                                    this.classList.add('btn-success');
                                    setTimeout(() => {
                                        this.innerHTML = originalText;
                                    }, 1000);
                                });
                            });

                        } catch(e){ console.warn('Error attaching price card handlers', e); }
                    }
                }
            } catch(e){ console.warn('Error rendering prices', e); }
            // set the qty input (default to 1 or product.qty if available)
            const productQtyEl = document.getElementById('product_qty');
            if(productQtyEl){
                productQtyEl.value = 1;
            }
            // set selling input to product selling price (from product table)
            const productSellingEl = document.getElementById('product_selling');
            if(productSellingEl){
                // Use product selling price if available, otherwise use per item cost
                let sellingPrice = 0;
                
                // First try to use product's selling price
                if(typeof p.selling !== 'undefined' && p.selling > 0){
                    sellingPrice = parseFloat(p.selling);
                } else {
                    // Fallback to per item cost if selling price is not set
                    const totalCost = (typeof p.cost !== 'undefined') ? parseFloat(p.cost) : 0;
                    const productQty = (typeof p.qty !== 'undefined') ? parseFloat(p.qty) : 0;
                    if(productQty > 0){
                        sellingPrice = totalCost / productQty;
                    }
                }
                
                productSellingEl.value = sellingPrice.toFixed(2);
            }
            // Lock or unlock selling input depending on product.is_active
            try {
                if(productSellingEl){
                    const active = (typeof p.is_active !== 'undefined') ? p.is_active : null;
                    // Lock selling if product is inactive (is_active = 0)
                    if(active === 0 || active === '0' || active === false){
                        productSellingEl.setAttribute('readonly', 'readonly');
                        productSellingEl.classList.add('bg-light');
                    } else {
                        productSellingEl.removeAttribute('readonly');
                        productSellingEl.classList.remove('bg-light');
                    }
                }
            } catch(e){ console.warn('selling readonly toggle error', e); }
            // enable add button
            const btn = document.getElementById('panelAddBtn');
            if(btn) { btn.disabled = false; }
        }
        psearch && psearch.addEventListener('input', function(){
            const q = this.value.toLowerCase();
            if(dropdown) {
                dropdown.remove();
                try { document.removeEventListener('click', dropdown._outsideHandler); } catch(e){}
            }
            dropdown = document.createElement('div');
            dropdown.className = 'list-group';
            dropdown.style.zIndex = 9999;
            dropdown.style.position = 'absolute';
            const rect = this.getBoundingClientRect();
            dropdown.style.width = rect.width + 'px';
            // Position relative to viewport + scroll
            dropdown.style.left = (rect.left + window.scrollX) + 'px';
            dropdown.style.top = (rect.bottom + window.scrollY) + 'px';
            dropdown.style.maxHeight = '300px';
            dropdown.style.overflowY = 'auto';
            document.body.appendChild(dropdown);

            // keyboard navigation helper
            let keyHandler = null;
            let focusedIndex = -1;

            // Split search query into words for flexible matching
            const searchWords = q.trim().split(/\s+/).filter(word => word.length > 0);

            const results = (window.PRODUCTS || []).filter(p => {
                const productName = (p.name || '').toLowerCase();
                const productCode = (p.code || '').toLowerCase();
                const productBarcode = String(p.barcode || '').toLowerCase();
                
                // Check if barcode or code matches exactly
                const barcodeMatch = productBarcode.includes(q);
                const codeMatch = productCode.includes(q);
                
                // Check if all search words are present in product name
                const allWordsMatch = searchWords.every(word => 
                    productName.includes(word)
                );
                
                return barcodeMatch || codeMatch || allWordsMatch;
            }).map(p => {
                // Add match score for sorting
                let score = 0;
                const name = (p.name||'').toLowerCase();
                const code = (p.code||'').toLowerCase();
                const barcode = String(p.barcode || '').toLowerCase();
                if (name === q) score = 10; // exact name match highest
                else if (code === q) score = 9; // exact code
                else if (barcode === q) score = 8; // exact barcode
                else if (name.startsWith(q)) score = 7; // name starts with
                else if (code.startsWith(q)) score = 6; // code starts with
                else if (barcode.startsWith(q)) score = 5; // barcode starts with
                else score = 4; // includes
                return { ...p, matchScore: score };
            }).sort((a, b) => b.matchScore - a.matchScore).slice(0,50); // Increased limit with scroll
            results.forEach(p => {
                const a = document.createElement('button');
                a.className = 'list-group-item list-group-item-action';
                a.type = 'button';
                a.innerText = (p.code ? '['+p.code+'] ' : '') + p.name;
                a.addEventListener('click', function(){
                    showProductDetails(p);
                    psearch.value = p.name;
                    dropdown.remove();
                    try { document.removeEventListener('click', dropdown._outsideHandler); } catch(e){}
                    try { psearch.removeEventListener('keydown', keyHandler); } catch(e){}
                    // after selecting via keyboard (Enter) or mouse, focus the Qty input for quick typing
                    try { const qtyEl = document.getElementById('product_qty'); if(qtyEl){ qtyEl.focus(); try{ qtyEl.select(); }catch(e){} } } catch(e){}
                });
                dropdown.appendChild(a);
            });

            // Auto-select the first (best) match to show in preview immediately
            if(results.length > 0){
                showProductDetails(results[0]);
            }

            // Do not auto-highlight any result initially
            try {
                const items = dropdown.querySelectorAll('.list-group-item');
                if(items && items.length){
                    focusedIndex = -1; // Start with no item highlighted
                    // No initial highlighting - wait for arrow key navigation
                }
            } catch(e){}

            // Close on outside click
            dropdown._outsideHandler = function(ev){
                if(!dropdown.contains(ev.target) && ev.target !== psearch){
                    dropdown.remove();
                    document.removeEventListener('click', dropdown._outsideHandler);
                    try { psearch.removeEventListener('keydown', keyHandler); } catch(e){}
                }
            };
            setTimeout(() => document.addEventListener('click', dropdown._outsideHandler));

                // attach keyboard handler to the search input so Arrow keys navigate the list
                try {
                    keyHandler = function(ev){
                        // defensive: dropdown may have been removed from DOM but handler still attached to the input
                        if(!dropdown) return;
                        const items = (dropdown.querySelectorAll && dropdown.querySelectorAll('.list-group-item')) || [];
                        if(!items || !items.length) return;
                    if(ev.key === 'ArrowDown' || ev.key === 'Down'){
                        ev.preventDefault();
                        focusedIndex = Math.min(focusedIndex + 1, items.length - 1);
                        items.forEach((it,i)=> it.classList.toggle('active', i === focusedIndex));
                        if(items[focusedIndex]) items[focusedIndex].scrollIntoView({block:'nearest'});
                        // Preview selected product name in input field only (don't select yet)
                        if(results[focusedIndex]){
                            psearch.value = results[focusedIndex].name;
                        }
                    } else if(ev.key === 'ArrowUp' || ev.key === 'Up'){
                        ev.preventDefault();
                        focusedIndex = Math.max(focusedIndex - 1, -1); // Allow going to -1 (no highlight)
                        if(focusedIndex >= 0){
                            items.forEach((it,i)=> it.classList.toggle('active', i === focusedIndex));
                            if(items[focusedIndex]) items[focusedIndex].scrollIntoView({block:'nearest'});
                            // Preview selected product name in input field only (don't select yet)
                            if(results[focusedIndex]){
                                psearch.value = results[focusedIndex].name;
                            }
                        } else {
                            // No item highlighted - clear input to original search term
                            items.forEach((it,i)=> it.classList.remove('active'));
                            // Keep the original search term in input when no item is selected
                        }
                    } else if(ev.key === 'Enter'){
                        ev.preventDefault();
                        // Only select if an item is actually highlighted (focusedIndex >= 0)
                        if(focusedIndex >= 0 && focusedIndex < results.length){
                            // Find the product that matches the current input value (set by arrow key navigation)
                            const currentInputValue = psearch.value.trim();
                            const selectedProduct = results.find(p => p.name === currentInputValue);
                            if(selectedProduct){
                                // Now surely select the product - call showProductDetails and complete selection
                                showProductDetails(selectedProduct);
                                psearch.value = selectedProduct.name;
                                dropdown.remove();
                                try { document.removeEventListener('click', dropdown._outsideHandler); } catch(e){}
                                try { psearch.removeEventListener('keydown', keyHandler); } catch(e){}
                                // focus qty
                                try { const qtyEl = document.getElementById('product_qty'); if(qtyEl){ qtyEl.focus(); try{ qtyEl.select(); }catch(e){} } } catch(e){}
                            }
                        }
                    } else if(ev.key === 'Escape'){
                        dropdown.remove();
                        try { document.removeEventListener('click', dropdown._outsideHandler); } catch(e){}
                        try { psearch.removeEventListener('keydown', keyHandler); } catch(e){}
                    }
                };
                // store key handler on dropdown so we can remove it later when hiding
                dropdown._keyHandler = keyHandler;
                // Attach key handler directly so arrow keys work even when global keyboard toggle is off
                psearch.addEventListener('keydown', keyHandler);
            } catch(e){}
        });

        // panel add button: add currently selected product from preview using qty input
        const panelAddBtn = document.getElementById('panelAddBtn');
        const productQtyEl = document.getElementById('product_qty');
        const productSellingEl = document.getElementById('product_selling');
        if(panelAddBtn){
            panelAddBtn.addEventListener('click', function(){
                if(typeof selectedProduct !== 'undefined' && selectedProduct){
                    let q = 1;
                    let s = null;
                    try { q = parseFloat(productQtyEl.value) || 1; } catch(e) { q = 1; }
                    try { s = parseFloat(productSellingEl.value); if(isNaN(s)) s = null; } catch(e){ s = null; }
                    // use selected price's market if available
                    const m = (typeof window.SELECTED_PRICE_MARKET !== 'undefined' && window.SELECTED_PRICE_MARKET) ? window.SELECTED_PRICE_MARKET : null;
                    addItem(selectedProduct, q, s, m);
                    // clear selected market after adding
                    try { window.SELECTED_PRICE_MARKET = null; } catch(e){}
                    // clear selling input and reset product search so user can start typing next product
                    try { if(productSellingEl) productSellingEl.value = ''; } catch(e){}
                    try { if(productQtyEl) productQtyEl.value = '1'; } catch(e){}
                    try { const psearchEl = document.getElementById('product_search'); if(psearchEl){ psearchEl.value = ''; psearchEl.focus(); try{ psearchEl.select(); }catch(e){} } } catch(e){}
                    // clear selected product and disable add button until a new product is selected
                    try { selectedProduct = null; window.selectedProduct = null; } catch(e){}
                    panelAddBtn.disabled = true;
                    // ensure selling input is editable again for next product
                    try { if(productSellingEl){ productSellingEl.removeAttribute('readonly'); productSellingEl.classList.remove('bg-light'); } } catch(e){}
                }
            });
        }

        // Qty input: Enter to focus selling input
        const qtyInput = document.getElementById('product_qty');
        if(qtyInput){
            qtyInput.addEventListener('keydown', function(ev){
                if(ev.key === 'Enter'){
                    ev.preventDefault();
                    const sellInput = document.getElementById('product_selling');
                    if(sellInput){ sellInput.focus(); try{ sellInput.select(); }catch(e){} }
                }
            });
        }

        // inline product-line Add button (same row)
        const productLineAddBtn = document.getElementById('productLineAddBtn');
        if(productLineAddBtn){
            productLineAddBtn.addEventListener('click', function(){
                const qText = (document.getElementById('product_search').value || '').trim();
                let productToAdd = selectedProduct || null;
                if(!productToAdd && qText){
                    productToAdd = findByBarcode(qText) || null;
                    if(!productToAdd){
                        const ql = qText.toLowerCase();
                        productToAdd = (window.PRODUCTS || []).find(p => (p.name||'').toLowerCase() === ql) || (window.PRODUCTS || []).find(p => (p.name||'').toLowerCase().includes(ql));
                    }
                }
                if(!productToAdd){ alert('Please select a product from the search results or type a valid product name/code/barcode.'); return; }
                let q = 1; let s = null;
                try { q = parseFloat(productQtyEl.value) || 1; } catch(e) { q = 1; }
                try { s = parseFloat(productSellingEl.value); if(isNaN(s)) s = null; } catch(e){ s = null; }
                const m = (typeof window.SELECTED_PRICE_MARKET !== 'undefined' && window.SELECTED_PRICE_MARKET) ? window.SELECTED_PRICE_MARKET : null;
                addItem(productToAdd, q, s, m);
                try { window.SELECTED_PRICE_MARKET = null; } catch(e){}
                try { const psearchEl = document.getElementById('product_search'); if(psearchEl){ psearchEl.value = ''; psearchEl.focus(); try{ psearchEl.select(); }catch(e){} } } catch(e){}
                // clear selling input and qty input
                try { if(productSellingEl) productSellingEl.value = ''; } catch(e){}
                try { if(productQtyEl) productQtyEl.value = '1'; } catch(e){}
                selectedProduct = null;
                try { window.selectedProduct = null; } catch(e){}
                try { panelAddBtn.disabled = true; } catch(e){}
                // ensure selling input is editable again for next product
                try { const ps = document.getElementById('product_selling'); if(ps){ ps.removeAttribute('readonly'); ps.classList.remove('bg-light'); } } catch(e){}
            });
        }

        // When Qty receives focus, hide any open product suggestion dropdown and clean up handlers
        try {
            if(productQtyEl){
                productQtyEl.addEventListener('focus', function(){
                    try {
                        if(dropdown){
                            // remove dropdown from DOM
                            dropdown.remove();
                            // remove document outside click handler if present
                            try { if(dropdown._outsideHandler) document.removeEventListener('click', dropdown._outsideHandler); } catch(e){}
                            // remove key handler attached to search input if we stored it
                            try { const psearchEl = document.getElementById('product_search'); if(psearchEl && dropdown._keyHandler) psearchEl.removeEventListener('keydown', dropdown._keyHandler); } catch(e){}
                            dropdown = null;
                        }
                    } catch(e){}
                });
            }
        } catch(e){}

        // When user presses Enter on Qty, focus Selling and open selling dropdown
        // Attach directly so this works regardless of ENABLE_INVOICE_KEYBOARD
        try {
            if(productQtyEl){
                productQtyEl.addEventListener('keydown', function(ev){
                    if(ev.key === 'Enter'){
                        ev.preventDefault();
                        try { if(productSellingEl){ productSellingEl.focus(); productSellingEl.select(); } } catch(e){}
                        // Removed: openSellingDropdown() call
                    }
                });
            }
        } catch(e){}

        // Show selling dropdown on ArrowDown when selling input is focused
        try {
            if(productSellingEl){
                // Prevent arrow keys from changing the numeric value in the input (browser default)
                // while preserving our dropdown/key navigation handlers.
                productSellingEl.addEventListener('keydown', function(ev){
                    if(ev.key === 'ArrowDown' || ev.key === 'ArrowUp' || ev.key === 'Down' || ev.key === 'Up'){
                        try { ev.preventDefault(); } catch(e){}
                    }
                });
                attachKeydown(productSellingEl, function(ev){
                    if(ev.key === 'ArrowDown' || ev.key === 'Down'){
                        ev.preventDefault();
                        // Removed: openSellingDropdown() call
                    }
                    // Ctrl+1 shortcut to apply first saved price
                    if(ev.ctrlKey && ev.key === '1'){
                        ev.preventDefault();
                        try {
                            const priceCards = document.querySelectorAll('#pd_price_list .price-card');
                            if(priceCards.length > 0){
                                priceCards[0].click();
                            }
                        } catch(e){ console.warn('Ctrl+1 shortcut failed', e); }
                    }
                });
                // When Enter is pressed in the selling input, add the currently selected product
                // unless the selling-price dropdown is open (in which case the dropdown's Enter handler will run)
                try {
                    productSellingEl.addEventListener('keydown', function(ev){
                        if(ev.key === 'Enter'){
                            ev.preventDefault();
                            try {
                                // If dropdown exists and an item is active, let the dropdown handle selection
                                const dd = document.getElementById('selling_price_dropdown');
                                if(dd){
                                    const active = dd.querySelector('.list-group-item.active');
                                    if(active){
                                        // simulate Enter on active item
                                        active.click();
                                        return;
                                    }
                                    // no active item: remove dropdown and proceed to add
                                    try { dd.remove(); } catch(e){}
                                }
                            } catch(e){}
                            // Primary add action: panel Add if available and a product is selected
                            try {
                                if(typeof selectedProduct !== 'undefined' && selectedProduct && panelAddBtn){
                                    panelAddBtn.click();
                                    return;
                                }
                            } catch(e){}
                            // Fallback: if inline add button exists, trigger it
                            try { if(productLineAddBtn) { productLineAddBtn.click(); return; } } catch(e){}
                            // Final fallback: attempt to trigger add via search value (simulate inline add)
                            try {
                                const q = (document.getElementById('product_search') || {}).value || '';
                                if(q && productLineAddBtn){ productLineAddBtn.click(); }
                            } catch(e){}
                        }
                    });
                } catch(e){}
                // Removed: dropdown on focus
            }
        } catch(e){}

        // allow Enter key in product search to select a matching product (barcode/code/name) and focus Qty
        // if a suggestion dropdown is open, let that handler manage Enter (it will select and focus Qty)
        try {
            const psearchEl = document.getElementById('product_search');
            if(psearchEl){
                // Attach directly so Enter works even when global keyboard shortcuts are disabled
                psearchEl.addEventListener('keydown', function(ev){
                    if(ev.key === 'Enter'){
                        ev.preventDefault();
                        const q = (psearchEl.value || '').trim();
                        if(!q) return;
                        // First: if the typed value exactly matches a barcode/id, select immediately (bypass dropdown)
                        let prod = findByBarcode(q) || null;
                        if(prod){
                            try { showProductDetails(prod); } catch(e){}
                            try { psearchEl.value = prod.name || ''; } catch(e){}
                            try { const qtyEl = document.getElementById('product_qty'); if(qtyEl){ qtyEl.focus(); try{ qtyEl.select(); }catch(e){} } } catch(e){}
                            return;
                        }
                        // If a suggestion dropdown is present, let its handler manage Enter (it will select & focus qty)
                        if(dropdown && dropdown.querySelectorAll && dropdown.querySelectorAll('.list-group-item').length){
                            return;
                        }

                        const ql = q.toLowerCase();
                        // try exact code match
                        prod = (window.PRODUCTS || []).find(p => String(p.code || '').toLowerCase() === ql) || null;
                        if(!prod){
                            // try exact name match, then includes
                            prod = (window.PRODUCTS || []).find(p => (p.name||'').toLowerCase() === ql) || (window.PRODUCTS || []).find(p => (p.name||'').toLowerCase().includes(ql)) || null;
                        }
                        if(prod){
                            try { showProductDetails(prod); } catch(e){}
                            try { psearchEl.value = prod.name || ''; } catch(e){}
                            try { const qtyEl = document.getElementById('product_qty'); if(qtyEl){ qtyEl.focus(); try{ qtyEl.select(); }catch(e){} } } catch(e){}
                        } else {
                            // no product found — notify the user (non-blocking)
                            try { alert('No product found for: "' + q + '"'); } catch(e){}
                        }
                    }
                });
            }
        } catch(e){}

        // Function to enable product search and related fields
        function enableProductFields() {
            const productSearch = document.getElementById('product_search');
            const productQty = document.getElementById('product_qty');
            const productSelling = document.getElementById('product_selling');
            
            if (productSearch) {
                productSearch.disabled = false;
                productSearch.placeholder = 'Type product name, code or barcode to search';
            }
            if (productQty) productQty.disabled = false;
            if (productSelling) productSelling.disabled = false;
        }
        
        // Function to disable product search and related fields
        function disableProductFields() {
            const productSearch = document.getElementById('product_search');
            const productQty = document.getElementById('product_qty');
            const productSelling = document.getElementById('product_selling');
            
            if (productSearch) {
                productSearch.disabled = true;
                productSearch.placeholder = 'Please select a customer first';
                productSearch.value = '';
            }
            if (productQty) productQty.disabled = true;
            if (productSelling) productSelling.disabled = true;
            
            // Hide customer balance row when no customer selected
            const balanceRow = document.getElementById('customerBalanceRow');
            if (balanceRow) balanceRow.style.display = 'none';
        }
        
        // Function to show customer balance
        function showCustomerBalance(balance) {
            const balanceRow = document.getElementById('customerBalanceRow');
            const balanceDisplay = document.getElementById('customerBalanceDisplay');
            
            if (balanceRow && balanceDisplay) {
                balanceDisplay.textContent = parseFloat(balance || 0).toFixed(2);
                balanceRow.style.display = 'table-row';
            }
        }

        // Wire customer typable dropdown
        const customerInput = document.getElementById('customer_search');
        const customerSelect = document.querySelector('select[name="customer_id"]');
            if(customerInput && customerSelect){
            const pre = customerSelect.options[customerSelect.selectedIndex];
            if(pre){
                const preContact = pre.getAttribute('data-contact') || '';
                const preBalance = pre.getAttribute('data-balance') || '0';
                // show only the customer name in the input; contact is shown in the separate display
                customerInput.value = pre.text || '';
                const contactDisplay = document.getElementById('customer_contact_display');
                if(contactDisplay) contactDisplay.innerText = preContact || '';
                
                // Enable product fields if customer is already selected on load
                if (customerSelect.value) {
                    enableProductFields();
                    showCustomerBalance(preBalance);
                }
            }

            createTypableDropdown(customerInput, window.CUSTOMERS || [], function(it){
                customerSelect.value = it.id;
                customerSelect.dispatchEvent(new Event('change', { bubbles: true }));
                // set visible input to name only
                customerInput.value = it.name || '';
                const contactDisplay = document.getElementById('customer_contact_display');
                if(contactDisplay) contactDisplay.innerText = it.contact || '';
                
                // Enable product fields and show balance when customer is selected
                enableProductFields();
                showCustomerBalance(it.balance || 0);
            });
            
            // Also enable fields if customer is already selected (on page load or when manually selecting from dropdown)
            customerSelect.addEventListener('change', function() {
                if (this.value) {
                    const selectedOption = this.options[this.selectedIndex];
                    const balance = selectedOption.getAttribute('data-balance') || '0';
                    enableProductFields();
                    showCustomerBalance(balance);
                } else {
                    disableProductFields();
                }
            });
        }

        // populate existing invoice items (edit mode)
        try {
            if(window.INVOICE_ITEMS && window.INVOICE_ITEMS.length){
                window.INVOICE_ITEMS.forEach(it => {
                    let prod = null;
                    if(it.item_id){ prod = (window.PRODUCTS || []).find(p => String(p.id) === String(it.item_id)); }
                    if(!prod){
                        prod = { id: it.item_id || null, code: it.code || '', barcode: it.barcode || '', name: it.name || it.item_name || 'Manual Item', cost: it.cost || 0, selling: it.selling_price || it.market_price || 0, market: it.market_price || 0 };
                    }
                    addItem(prod, parseFloat(it.qty || 1), (typeof it.selling_price !== 'undefined') ? it.selling_price : null, true);
                    const tr = document.querySelector('#itemsTable tbody tr:last-child');
                    if(tr){
                        try { tr.querySelector('.item-cost').value = (typeof it.cost !== 'undefined') ? it.cost : (prod.cost || 0); } catch(e){}
                        try { tr.querySelector('.item-discount').value = (typeof it.discount !== 'undefined') ? it.discount : 0; } catch(e){}
                        try { tr.querySelector('.item-qty').value = it.qty || 1; } catch(e){}
                        try {
                            const mEl = tr.querySelector('.item-market');
                            if(mEl){ mEl.value = (typeof it.market_price !== 'undefined') ? parseFloat(it.market_price).toFixed(2) : ((typeof prod.market !== 'undefined') ? parseFloat(prod.market).toFixed(2) : ''); }
                        } catch(e){}
                        try { const codeCell = tr.querySelector('.item-code'); if(codeCell) codeCell.innerText = prod.code || (it.code || ''); } catch(e){}
                        recalc();
                    }
                });
            }
        } catch(e){ console.warn('Error populating invoice items', e); }

        // "Add Manual Item" button removed — manual-item flow disabled

        // Validation function for required fields
        function validateInvoiceForm() {
            // Check Invoice Number
            const invoiceNumber = document.getElementById('invoice_number')?.value?.trim();
            if (!invoiceNumber) {
                alert('ඉන්වොයිස් අංකය අවශ්‍ය වේ!\nInvoice Number is required!');
                document.getElementById('invoice_number')?.focus();
                return false;
            }

            // Check Date & Time (only for create page, skip if field doesn't exist in edit mode)
            const dateTimeField = document.getElementById('date_time');
            if (dateTimeField) {
                const dateTime = dateTimeField.value?.trim();
                if (!dateTime) {
                    alert('දිනය සහ වේලාව අවශ්‍ය වේ!\nDate & Time is required!');
                    return false;
                }
            }

            // Check if at least one product is added
            const itemsTable = document.getElementById('itemsTable');
            const itemRows = itemsTable?.querySelectorAll('tbody tr');
            if (!itemRows || itemRows.length === 0) {
                alert('අවම වශයෙන් එක ප්‍රොඩක්ට්වත් එකතු කරන්න!\nAdd at least one product!');
                document.getElementById('product_search')?.focus();
                return false;
            }

            // Payment validation: cash and/or card may be used. If total paid is less than net total,
            // require a customer selection so this becomes a credit sale.
            const cashVal = parseFloat(document.getElementById('payment_cashpaid')?.value || 0) || 0;
            const cardVal = parseFloat(document.getElementById('card_amount')?.value || 0) || 0;
            const totalPaid = cashVal + cardVal;
            // read net total from the summary (calculated earlier by recalc)
            const netTotalText = (document.getElementById('summary_nettotal')?.innerText || '0');
            const netTotal = parseFloat(netTotalText) || 0;

            const customerSelectVal = document.querySelector('select[name="customer_id"]').value || '';
            // Require customer selection always on invoice create
            if (!customerSelectVal || customerSelectVal.trim() === '') {
                alert('Customer selection is required.\nකරුණාකර පාරිභෝගිකයෙක් තෝරන්න.');
                document.getElementById('customer_search')?.focus();
                return false;
            }

            return true;
        }

        // Function to save invoice with AJAX (no page refresh)
        function saveInvoice() {
            if (!validateInvoiceForm()) {
                return;
            }

            // Show loading state
            const saveBtn = document.getElementById('saveInvoice');
            const originalText = saveBtn.innerText;
            saveBtn.innerText = 'Saving...';
            saveBtn.disabled = true;

            const items = [];
            document.querySelectorAll('#itemsTable tbody tr').forEach(tr => {
                // Skip customer balance row
                if (tr.id === 'customerBalanceRow') return;
                
                // Skip rows without proper item structure
                const qtyEl = tr.querySelector('.item-qty');
                const sellingEl = tr.querySelector('.item-selling');
                if (!qtyEl || !sellingEl) return;
                
                items.push({
                    item_id: tr.querySelector('td').dataset.id || null,
                    qty: parseFloat(qtyEl.value) || 0,
                    warranty: parseInt(tr.querySelector('.item-warranty')?.value) || null,
                    cost: parseFloat(tr.querySelector('.item-cost')?.value) || 0,
                    selling_price: parseFloat(sellingEl.value) || 0,
                    discount: parseFloat(tr.querySelector('.item-discount')?.value) || 0,
                    total_value: parseFloat(tr.querySelector('.item-total')?.innerText) || 0
                });
            });

            // Collect form data
            const formData = new FormData();
            formData.append('invoice_number', document.getElementById('invoice_number').value);
            
            // Handle customer_id - send null if empty
            const customerId = document.querySelector('select[name="customer_id"]').value;
            if (customerId && customerId.trim() !== '') {
                formData.append('customer_id', customerId);
            }

            // Include selected salesman_id if present
            const salesmanSelect = document.querySelector('select[name="salesman_id"]');
            if (salesmanSelect) {
                const salesmanId = salesmanSelect.value;
                if (salesmanId && salesmanId.trim() !== '') {
                    formData.append('salesman_id', salesmanId);
                }
            }
            
            // Send current date/time
            const dateTimeValue = document.getElementById('date_time')?.value || '';
            if (dateTimeValue) {
                formData.append('date_time', dateTimeValue);
            }

            // Always include selected loan_frequency (if present) so edit/create persist the value
            try {
                const freqVal = document.getElementById('loan_frequency')?.value || document.getElementById('loan_frequency_edit')?.value || null;
                if (freqVal) formData.append('loan_frequency', freqVal);
            } catch(e) { /* non-fatal */ }
            
            formData.append('items', JSON.stringify(items));

            // Invoice mode + loan details (if user selected Loan)
            try {
                const invMode = document.querySelector('input[name="invoice_mode"]:checked')?.value || 'cash';
                formData.append('invoice_mode', invMode);
                if(invMode === 'loan'){
                    // Ensure any user-edited schedule table on the Edit page is normalized and serialized into the payload
                    try {
                        // Recompute totals and normalize pending months to avoid zero-values being saved
                        try { if (typeof normalizeLoanScheduleTotals === 'function') normalizeLoanScheduleTotals(); } catch(_) {}
                        try { if (typeof rebuildLoanScheduleTable === 'function') rebuildLoanScheduleTable(); } catch(_) {}
                        try { if (typeof recalc === 'function') recalc(); } catch(_) {}

                        // Normalize any edited schedule table into a canonical JSON hidden field.
                        // The Edit page uses #loanScheduleTableEdit while Create uses #loanScheduleTable.
                        try {
                            const tableEdit = document.querySelector('#loanScheduleTableEdit tbody');
                            const tableCreate = document.querySelector('#loanScheduleTable tbody');
                            const table = tableEdit || tableCreate;
                            if (table) {
                                const rows = table.querySelectorAll('tr');
                                const arr = [];
                                // decide which column holds due_date: edit table has 5 cols (due at index 4), create table has 3 cols (due at index 2)
                                const dueIndex = (table === tableEdit) ? 4 : 2;
                                rows.forEach(r => {
                                    const tds = r.querySelectorAll('td');
                                    if (tds && tds.length >= 2) {
                                        const inst = parseInt((tds[0].innerText || '').trim()) || null;
                                        const amt = parseFloat((tds[1].innerText || '').replace(/,/g,'')) || 0;
                                        const due = (tds[dueIndex] && (tds[dueIndex].innerText || '').trim()) ? (tds[dueIndex].innerText || '').trim() : null;
                                        if (inst) {
                                            const obj = { installment: inst, amount: amt };
                                            if (due) obj.due_date = due;
                                            arr.push(obj);
                                        }
                                    }
                                });
                                // write back into hidden canonical field so server receives the exact schedule
                                const hs = document.getElementById('loan_schedule');
                                if (hs) hs.value = JSON.stringify(arr);
                            }
                        } catch(e) { /* non-fatal */ }
                    } catch(e) { /* non-fatal */ }

                    const down = parseFloat(document.getElementById('loan_downpayment')?.value || 0) || 0;
                    // Count actual rows in schedule table for accurate months value (support create & edit tables)
                    const scheduleTableEdit = document.querySelector('#loanScheduleTableEdit tbody');
                    const scheduleTableCreate = document.querySelector('#loanScheduleTable tbody');
                    let actualMonths = 1;
                    const scheduleTable = scheduleTableEdit || scheduleTableCreate;
                    if (scheduleTable) {
                        const tableRows = scheduleTable.querySelectorAll('tr');
                        if (tableRows && tableRows.length > 0) {
                            actualMonths = tableRows.length;
                        }
                    }
                    const months = actualMonths || parseInt(document.getElementById('loan_months')?.value || 1) || 1;
                    const netTotal = parseFloat((document.getElementById('summary_nettotal')?.innerText || '0')) || 0;
                    // compute schedule using helper if available; otherwise use a local fallback
                    let schedule = [];
                    try {
                        const frequency = document.getElementById('loan_frequency')?.value || document.getElementById('loan_frequency_edit')?.value || 'month';
                        // Ensure selected frequency is submitted so backend can persist it
                        try { formData.append('loan_frequency', frequency); } catch(e) { /* non-fatal */ }
                        if (typeof computeLoanSchedule === 'function') {
                                schedule = computeLoanSchedule(netTotal, down, months, frequency);
                            } else {
                            // Local fallback (same logic as computeLoanSchedule)
                            const remaining = Math.max(0, netTotal - down);
                            const base = months > 0 ? (remaining / months) : remaining;
                            const monthly = Math.round(base * 100) / 100;
                            let distributed = 0;
                            for (let i = 1; i <= months; i++) {
                                let amt = (i === months) ? parseFloat((remaining - distributed).toFixed(2)) : parseFloat(monthly.toFixed(2));
                                schedule.push({ installment: i, amount: amt });
                                distributed += amt;
                            }
                        }
                    } catch(e) { schedule = []; }
                    const monthly = schedule.length ? schedule[0].amount : parseFloat(((netTotal - down) / months) || 0).toFixed(2);
                    formData.append('loan_downpayment', down);
                    formData.append('loan_months', months);
                    formData.append('loan_monthly_amount', parseFloat(monthly));
                    formData.append('loan_balance', parseFloat(Math.max(0, netTotal - down)).toFixed(2));
                    // prefer the schedule serialized into hidden field (if present), otherwise fall back to computed schedule
                    const hsFinal = document.getElementById('loan_schedule');
                    if (hsFinal && hsFinal.value && hsFinal.value.trim() !== '') {
                        formData.append('loan_schedule', hsFinal.value);
                    } else {
                        formData.append('loan_schedule', JSON.stringify(schedule));
                    }
                }
            } catch(e){ /* non-fatal */ }

            // Add CSRF token
            const csrfToken = document.querySelector('meta[name="csrf-token"]');
            if (csrfToken) {
                formData.append('_token', csrfToken.getAttribute('content'));
            }

            // Include payment values based on mode
            try {
                const invMode = document.querySelector('input[name="invoice_mode"]:checked')?.value || 'cash';
                formData.append('invoice_mode', invMode);
                let downPayment = 0;
                let paymentType = 'cash';

                // Treat Preorder like Cash for immediate paid amount handling: allow submitting a cash_payment
                if (invMode === 'cash' || invMode === 'preorder') {
                    paymentType = document.getElementById('payment_type')?.value || document.getElementById('payment_type_edit')?.value || 'cash';
                    downPayment = parseFloat(document.getElementById('payment_cashpaid')?.value || 0) || 0;
                    formData.append('cash_payment', downPayment.toFixed(2));
                } else if (invMode === 'loan') {
                    // For loan mode, preserve the actual payment instrument selected by the user
                    // (cash, card, bank). Do not overwrite it with the mode name 'loan'.
                    paymentType = document.getElementById('payment_type')?.value || document.getElementById('payment_type_edit')?.value || 'cash';
                    downPayment = parseFloat(document.getElementById('loan_downpayment')?.value || 0) || 0;
                    formData.append('loan_downpayment', downPayment.toFixed(2));
                }

                formData.append('payment_type', paymentType);
                formData.append('down_payment', downPayment.toFixed(2));
                // Serialize any ad-hoc payments tracked by the payments[] array
                try { formData.append('payments', JSON.stringify(payments || [])); } catch(e){ formData.append('payments', '[]'); }
            } catch(e) { /* non-fatal */ }

            const url = isEdit ?
                window.location.pathname.replace('/edit', '') :
                document.getElementById('invoiceForm').action;

            // For edit operations, include _method=PUT to simulate PUT request
            if (isEdit) {
                formData.append('_method', 'PUT');
            }

            // Send AJAX request
            fetch(url, {
                method: 'POST', // Always use POST, Laravel handles _method
                body: formData,
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                    'Accept': 'application/json'
                }
            })
            .then(response => {
                if (!response.ok) {
                    // If response is not ok, try to parse error
                    return response.json().then(err => {
                        throw new Error(err.message || 'Server error');
                    });
                }
                return response.json();
            })
            .then(data => {
                if (data.success) {
                    // Show success alert
                    alert('Invoice saved successfully!');
                    
                    // Redirect after a short delay to ensure user sees the alert
                    setTimeout(() => {
                        if (isEdit) {
                            window.location.href = <?php echo json_encode(route("invoices.index")); ?>;
                        } else {
                            window.location.href = <?php echo json_encode(route("invoices.create")); ?>;
                        }
                    }, 500); // 500ms delay

                    // No auto-print - user can manually print from Last Bill Details or navigate to show page
                } else {
                    alert('Error: ' + (data.message || 'Unknown error occurred.'));
                }
            })
            .catch(error => {
                console.error('Error:', error);
                const errorMessage = error.message || 'Server error occurred. Please try again.';
                alert('Error: ' + errorMessage);
            })
            .finally(() => {
                // Reset button state
                saveBtn.innerText = originalText;
                saveBtn.disabled = false;
            });
        }

        // Save button click handler
        document.getElementById('saveInvoice').addEventListener('click', function(e){
            e.preventDefault();
            saveInvoice();
        });

        // Enter key on Cash Paid input to save invoice (prevent form submission)
        document.getElementById('payment_cashpaid').addEventListener('keydown', function(e){
            if (e.key === 'Enter' || e.keyCode === 13) {
                e.preventDefault();
                e.stopImmediatePropagation();
                saveInvoice();
                return false;
            }
        });

        document.getElementById('payment_cashpaid').addEventListener('keypress', function(e){
            if (e.key === 'Enter' || e.keyCode === 13) {
                e.preventDefault();
                e.stopImmediatePropagation();
                return false;
            }
        });

        document.getElementById('payment_cashpaid').addEventListener('keyup', function(e){
            if (e.key === 'Enter' || e.keyCode === 13) {
                e.preventDefault();
                e.stopImmediatePropagation();
                return false;
            }
        });

        // Initialize balance calculation for edit mode (when page loads with existing data)
        setTimeout(() => {
            const cashPaidEl = document.getElementById('payment_cashpaid');
            if (cashPaidEl && cashPaidEl.value) {
                // Trigger balance calculation for existing cash paid value
                const netTotalEl = document.getElementById('summary_nettotal');
                const summaryBalanceEl = document.getElementById('summary_balance');
                
                const netTotal = parseFloat(netTotalEl ? netTotalEl.innerText : 0) || 0;
                const cashPaid = parseFloat(cashPaidEl.value || 0) || 0;
                const remaining = Math.max(0, netTotal - cashPaid);

                if(summaryBalanceEl) summaryBalanceEl.innerText = remaining.toFixed(2);
            }
        }, 100);
    });
</script>
<?php /**PATH D:\ONLINE SYSTEMS ORIGINALS\demo perera\test 06-05-2026\resources\views/invoices/create_js_partial.blade.php ENDPATH**/ ?>