<?xml version="1.0" encoding="utf-8"?>
<odoo>

    <!-- ═══════════════════════════════════════════════════════════
         Portal "My Inventory" link on portal home
         ═══════════════════════════════════════════════════════════ -->

    <template id="portal_my_home_inventory" name="Show Inventory"
              inherit_id="portal.portal_my_home"
              customize_show="True" priority="60">
        <xpath expr="//div[hasclass('o_portal_docs')]" position="before">
            <t t-call="portal.portal_docs_entry">
                <t t-set="icon" t-value="'/fusion_inventory/static/description/icon.png'"/>
                <t t-set="title">Inventory Sheet</t>
                <t t-set="url" t-value="'/my/inventory'"/>
                <t t-set="text">View live inventory, search products, and book items</t>
                <t t-set="placeholder_count" t-value="'fi_inventory'"/>
            </t>
        </xpath>
    </template>

    <!-- ═══════════════════════════════════════════════════════════
         Portal Inventory Sheet - Main Page
         ═══════════════════════════════════════════════════════════ -->

    <template id="portal_inventory_sheet" name="Inventory Sheet">
        <t t-call="portal.portal_layout">
            <t t-set="breadcrumbs_searchbar" t-value="True"/>

            <div class="container-fluid px-2 px-md-4 py-3" id="fi_inventory_app">

                <!-- ── Header ── -->
                <div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
                    <h3 class="mb-0">Inventory Sheet</h3>
                    <small class="text-muted">
                        <span id="fi_last_update">Just now</span>
                        <span class="spinner-border spinner-border-sm ms-1 d-none"
                              id="fi_loading" role="status"/>
                    </small>
                </div>

                <!-- ── Search + Filters ── -->
                <div class="row g-2 mb-3">
                    <div class="col-12 col-md-5">
                        <div class="input-group">
                            <input type="text" id="fi_search" class="form-control"
                                   placeholder="Search by name, SKU, or serial..."
                                   t-att-value="search"/>
                            <button class="btn btn-primary" id="fi_search_btn"
                                    type="button">
                                <i class="fa fa-search"/>
                            </button>
                        </div>
                    </div>
                    <div class="col-12 col-md-4 position-relative">
                        <input type="text" id="fi_category_search" class="form-control"
                               placeholder="Search categories..." autocomplete="off"/>
                        <input type="hidden" id="fi_category_filter" value=""/>
                        <div id="fi_category_dropdown"
                             class="position-absolute w-100 bg-white border rounded-bottom shadow-sm d-none"
                             style="z-index:1050; max-height:250px; overflow-y:auto; top:100%;">
                        </div>
                    </div>
                    <div class="col-12 col-md-3" t-if="has_sync">
                        <select id="fi_warehouse_filter" class="form-select">
                            <option value="all"
                                    t-att-selected="warehouse_filter == 'all'">All Locations</option>
                            <option value="local"
                                    t-att-selected="warehouse_filter == 'local'">Local Only</option>
                            <option value="remote"
                                    t-att-selected="warehouse_filter == 'remote'">Remote Only</option>
                            <t t-foreach="all_warehouses" t-as="wh">
                                <option t-att-value="wh['id']">
                                    <t t-if="wh['type'] == 'remote'">&#x1F517; </t>
                                    <t t-esc="wh['name']"/>
                                    <t t-if="wh['company']"> (<t t-esc="wh['company']"/>)</t>
                                </option>
                            </t>
                        </select>
                    </div>
                </div>

                <!-- ── Compact table styles ── -->
                <style>
                    #fi_inventory_table {
                        font-size: 0.8rem;
                        table-layout: fixed;
                        width: 100%;
                    }
                    #fi_inventory_table th,
                    #fi_inventory_table td {
                        padding: 0.3rem 0.4rem;
                        overflow: hidden;
                        text-overflow: ellipsis;
                        vertical-align: middle;
                    }
                    #fi_inventory_table .fi-col-product {
                        width: auto;
                        white-space: normal;
                        word-wrap: break-word;
                    }
                    #fi_inventory_table .fi-col-sku {
                        width: 80px;
                        white-space: nowrap;
                    }
                    #fi_inventory_table .fi-col-cat {
                        width: 100px;
                        white-space: normal;
                        word-wrap: break-word;
                    }
                    #fi_inventory_table .fi-col-num {
                        width: 50px;
                        white-space: nowrap;
                        text-align: right;
                    }
                    #fi_inventory_table .fi-col-price {
                        width: 65px;
                        white-space: nowrap;
                        text-align: right;
                    }
                    #fi_inventory_table .fi-col-action {
                        width: 60px;
                        text-align: center;
                        white-space: nowrap;
                    }
                    #fi_inventory_table thead th {
                        font-size: 0.72rem;
                        text-transform: uppercase;
                        letter-spacing: 0.02em;
                        border-bottom: 2px solid #adb5bd;
                    }
                    #fi_inventory_table .badge {
                        font-size: 0.7rem;
                        padding: 0.15em 0.4em;
                    }
                    #fi_inventory_table .btn-sm {
                        font-size: 0.68rem;
                        padding: 0.1rem 0.35rem;
                    }
                </style>

                <!-- ── Legend ── -->
                <div class="d-flex flex-wrap gap-3 mb-3 small">
                    <span><span class="badge bg-success">&#9679;</span> In Stock</span>
                    <span><span class="badge bg-warning text-dark">&#9679;</span> Booked</span>
                    <span><span class="badge bg-info">&#9679;</span> Incoming (PO)</span>
                    <span><span class="badge bg-danger">&#9679;</span> Out of Stock</span>
                    <span t-if="has_sync"><span class="badge bg-purple" style="background:#6f42c1!important;">&#9679;</span> Remote</span>
                </div>

                <!-- ══════════ Desktop Table ══════════ -->
                <div class="table-responsive d-none d-md-block">
                    <table class="table table-hover table-sm table-bordered align-middle"
                           id="fi_inventory_table">
                        <thead class="table-light">
                            <tr>
                                <th class="fi-col-product">Product</th>
                                <th class="fi-col-sku">SKU</th>
                                <th class="fi-col-cat">Category</th>
                                <th class="fi-col-num">Local</th>
                                <th class="fi-col-num">Avail</th>
                                <th class="fi-col-num" t-if="has_sync">Remote</th>
                                <th class="fi-col-num" t-if="has_sync">Total</th>
                                <th class="fi-col-num">Booked</th>
                                <th class="fi-col-num">Incom.</th>
                                <th class="fi-col-price">Price</th>
                                <th class="fi-col-num">Margin</th>
                                <th class="fi-col-action">Action</th>
                            </tr>
                        </thead>
                        <tbody id="fi_table_body">
                            <t t-foreach="products" t-as="p">
                                <tr t-att-data-id="p['id']" t-att-data-tmpl="p.get('tmpl_id', 0)">
                                    <td class="fi-col-product">
                                        <strong t-esc="p['name']"/>
                                    </td>
                                    <td class="fi-col-sku text-muted">
                                        <t t-esc="p['default_code']"/>
                                    </td>
                                    <td class="fi-col-cat"><t t-esc="p['category']"/></td>
                                    <td class="fi-col-num"><t t-esc="p['qty_on_hand']"/></td>
                                    <td class="fi-col-num">
                                        <span t-attf-class="fw-bold #{'text-danger' if p['available_qty'] &lt;= 0 else 'text-success'}">
                                            <t t-esc="p['available_qty']"/>
                                        </span>
                                    </td>
                                    <td class="fi-col-num" t-if="has_sync">
                                        <span t-if="p.get('remote_qty', 0) > 0"
                                              class="badge text-white fi-remote-badge"
                                              style="background:#6f42c1; cursor:pointer;"
                                              t-att-title="', '.join([w['warehouse'] + ': ' + str(w['qty']) for w in p.get('remote_warehouses', [])])">
                                            <t t-esc="p['remote_qty']"/>
                                        </span>
                                        <span t-if="p.get('remote_qty', 0) &lt;= 0"
                                              class="text-muted">0</span>
                                    </td>
                                    <td class="fi-col-num" t-if="has_sync">
                                        <strong><t t-esc="p.get('total_qty', p['qty_on_hand'])"/></strong>
                                    </td>
                                    <td class="fi-col-num">
                                        <span t-if="p['booked_qty'] > 0"
                                              class="badge bg-warning text-dark">
                                            <t t-esc="p['booked_qty']"/>
                                        </span>
                                    </td>
                                    <td class="fi-col-num">
                                        <span t-if="p['shadow_qty'] > 0"
                                              class="badge bg-info">
                                            <t t-esc="p['shadow_qty']"/>
                                        </span>
                                    </td>
                                    <td class="fi-col-price">
                                        $<t t-esc="'%.2f' % p['sale_price']"/>
                                    </td>
                                    <td class="fi-col-num">
                                        <span t-attf-class="badge #{'bg-success' if p['margin_pct'] > 0 else 'bg-secondary'}">
                                            <t t-esc="'%.1f' % p['margin_pct']"/>%
                                        </span>
                                    </td>
                                    <td class="fi-col-action">
                                        <div class="btn-group btn-group-sm">
                                            <button t-if="p['available_qty'] > 0"
                                                    class="btn btn-sm btn-outline-primary fi-book-btn"
                                                    t-att-data-id="p['id']"
                                                    t-att-data-name="p['name']">
                                                Book
                                            </button>
                                            <button t-if="has_sync and p.get('remote_qty', 0) > 0 and p['id'] > 0"
                                                    class="btn btn-sm btn-outline-secondary fi-transfer-btn"
                                                    t-att-data-id="p['id']"
                                                    t-att-data-name="p['name']"
                                                    t-att-data-remote-qty="p['remote_qty']"
                                                    title="Transfer from remote">
                                                <i class="fa fa-exchange"/>
                                            </button>
                                        </div>
                                        <span t-if="p['available_qty'] &lt;= 0 and p.get('remote_qty', 0) &lt;= 0"
                                              class="text-muted small">--</span>
                                    </td>
                                </tr>
                            </t>
                            <!-- Remote-only products -->
                            <t t-foreach="remote_only_products" t-as="rp">
                                <tr class="table-light fst-italic" t-att-data-id="0">
                                    <td class="fi-col-product">
                                        <span class="badge bg-secondary me-1">Remote</span>
                                        <t t-esc="rp['name']"/>
                                    </td>
                                    <td class="fi-col-sku text-muted"><t t-esc="rp['default_code']"/></td>
                                    <td class="fi-col-cat"><t t-esc="rp['category']"/></td>
                                    <td class="fi-col-num text-muted">0</td>
                                    <td class="fi-col-num text-muted">0</td>
                                    <td class="fi-col-num" t-if="has_sync">
                                        <span class="badge text-white" style="background:#6f42c1;">
                                            <t t-esc="rp['remote_qty']"/>
                                        </span>
                                    </td>
                                    <td class="fi-col-num" t-if="has_sync">
                                        <strong><t t-esc="rp['total_qty']"/></strong>
                                    </td>
                                    <td class="fi-col-num">-</td>
                                    <td class="fi-col-num">-</td>
                                    <td class="fi-col-price">$<t t-esc="'%.2f' % rp['sale_price']"/></td>
                                    <td class="fi-col-num">-</td>
                                    <td class="fi-col-action text-muted small">
                                        <t t-esc="rp.get('config_name', '')"/>
                                    </td>
                                </tr>
                            </t>
                        </tbody>
                    </table>
                </div>

                <!-- ══════════ Mobile Cards ══════════ -->
                <div class="d-block d-md-none" id="fi_mobile_cards">
                    <t t-foreach="products" t-as="p">
                        <div class="card mb-2 fi-card" t-att-data-id="p['id']"
                             t-attf-style="border-left: 4px solid #{'#ffc107' if p['booked_qty'] > 0 else '#198754' if p['available_qty'] > 0 else '#dc3545'};">
                            <div class="card-body py-2 px-3">
                                <div class="d-flex justify-content-between align-items-start">
                                    <div style="max-width:65%;">
                                        <div class="fw-bold text-truncate">
                                            <t t-esc="p['name']"/>
                                        </div>
                                        <small class="text-muted">
                                            <t t-esc="p['default_code']"/>
                                            <t t-if="p['category']"> | <t t-esc="p['category']"/></t>
                                        </small>
                                    </div>
                                    <div class="text-end">
                                        <div class="fw-bold">$<t t-esc="'%.2f' % p['sale_price']"/></div>
                                        <span t-attf-class="badge #{'bg-success' if p['margin_pct'] > 0 else 'bg-secondary'} small">
                                            <t t-esc="'%.1f' % p['margin_pct']"/>%
                                        </span>
                                    </div>
                                </div>
                                <div t-attf-class="row g-1 mt-2 text-center #{'row-cols-5' if has_sync else ''}" style="font-size:.85rem;">
                                    <div t-attf-class="#{'col' if has_sync else 'col-3'}">
                                        <div class="fw-bold"><t t-esc="p['qty_on_hand']"/></div>
                                        <div class="text-muted" style="font-size:.7rem;">Local</div>
                                    </div>
                                    <div t-attf-class="#{'col' if has_sync else 'col-3'}">
                                        <div t-attf-class="fw-bold #{'text-danger' if p['available_qty'] &lt;= 0 else ''}">
                                            <t t-esc="p['available_qty']"/>
                                        </div>
                                        <div class="text-muted" style="font-size:.7rem;">Avail</div>
                                    </div>
                                    <div t-attf-class="#{'col' if has_sync else 'col-3'}" t-if="has_sync">
                                        <div class="fw-bold" style="color:#6f42c1;">
                                            <t t-esc="p.get('remote_qty', 0)"/>
                                        </div>
                                        <div class="text-muted" style="font-size:.7rem;">Remote</div>
                                    </div>
                                    <div t-attf-class="#{'col' if has_sync else 'col-3'}">
                                        <div class="fw-bold"><t t-esc="p['booked_qty']"/></div>
                                        <div class="text-muted" style="font-size:.7rem;">Booked</div>
                                    </div>
                                    <div t-attf-class="#{'col' if has_sync else 'col-3'}">
                                        <div class="fw-bold"><t t-esc="p['shadow_qty']"/></div>
                                        <div class="text-muted" style="font-size:.7rem;">Incoming</div>
                                    </div>
                                </div>
                                <div class="mt-2 text-end">
                                    <div class="btn-group btn-group-sm">
                                        <button t-if="p['available_qty'] > 0"
                                                class="btn btn-sm btn-outline-primary fi-book-btn"
                                                t-att-data-id="p['id']"
                                                t-att-data-name="p['name']">
                                            Book
                                        </button>
                                        <button t-if="has_sync and p.get('remote_qty', 0) > 0 and p['id'] > 0"
                                                class="btn btn-sm btn-outline-secondary fi-transfer-btn"
                                                t-att-data-id="p['id']"
                                                t-att-data-name="p['name']"
                                                t-att-data-remote-qty="p['remote_qty']">
                                            <i class="fa fa-exchange"/> Transfer
                                        </button>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </t>
                </div>

                <!-- ══════════ Pagination ══════════ -->
                <nav class="mt-3" id="fi_pagination">
                </nav>

                <div class="text-muted small text-center mt-2">
                    <span id="fi_count_text">Showing <t t-esc="len(products)"/> of <t t-esc="total_products"/> products</span>
                    | Auto-refreshes every 30 seconds
                </div>

            </div>

            <!-- ══════════ Transfer Modal ══════════ -->
            <div class="modal fade" id="fi_transfer_modal" tabindex="-1">
                <div class="modal-dialog modal-dialog-centered">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h5 class="modal-title">Transfer from Remote</h5>
                            <button type="button" class="btn-close" data-bs-dismiss="modal"/>
                        </div>
                        <div class="modal-body">
                            <p>
                                Transfer <strong id="fi_transfer_product_name"></strong>
                                from remote inventory.
                            </p>
                            <div class="mb-3">
                                <label class="form-label">Available at remote:</label>
                                <span id="fi_transfer_remote_qty" class="fw-bold"></span>
                            </div>
                            <div class="mb-3">
                                <label for="fi_transfer_qty" class="form-label">Quantity to transfer:</label>
                                <input type="number" id="fi_transfer_qty" class="form-control"
                                       min="1" value="1"/>
                            </div>
                            <div id="fi_transfer_result" class="d-none">
                                <div id="fi_transfer_success" class="alert alert-success d-none"></div>
                                <div id="fi_transfer_error" class="alert alert-danger d-none"></div>
                            </div>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                            <button type="button" class="btn btn-primary" id="fi_transfer_confirm_btn">
                                <span class="spinner-border spinner-border-sm d-none me-1" id="fi_transfer_spinner"/>
                                Confirm Transfer
                            </button>
                        </div>
                    </div>
                </div>
            </div>

            <!-- ══════════ JavaScript: Polling + Booking + Transfer ══════════ -->
            <script type="text/javascript">
                (function () {
                    'use strict';

                    var refreshInterval = 30000;
                    var timer = null;
                    var searchTimer = null;
                    var currentPage = <t t-esc="page"/>;
                    var hasSync = <t t-esc="'true' if has_sync else 'false'"/>;

                    function updateTimestamp() {
                        var el = document.getElementById('fi_last_update');
                        if (el) el.textContent = new Date().toLocaleTimeString();
                    }

                    function showLoading(show) {
                        var el = document.getElementById('fi_loading');
                        if (el) el.classList.toggle('d-none', !show);
                    }

                    function refreshData(resetPage) {
                        if (resetPage) currentPage = 1;
                        var searchEl = document.getElementById('fi_search');
                        var catEl = document.getElementById('fi_category_filter');
                        var whEl = document.getElementById('fi_warehouse_filter');
                        var search = searchEl ? searchEl.value.trim() : '';
                        var catId = catEl ? catEl.value.trim() : '';
                        var warehouse = whEl ? whEl.value : 'all';

                        showLoading(true);

                        fetch('/my/inventory/data', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({
                                jsonrpc: '2.0',
                                method: 'call',
                                params: {
                                    search: search,
                                    category_ids: catId ? [parseInt(catId)] : null,
                                    page: currentPage,
                                    warehouse: warehouse
                                }
                            })
                        })
                        .then(function(r) { return r.json(); })
                        .then(function(data) {
                            showLoading(false);
                            updateTimestamp();
                            if (data.result &amp;&amp; data.result.products) {
                                rebuildTable(data.result.products);
                                rebuildMobileCards(data.result.products);
                                updateCount(data.result.products.length, data.result.total);
                                rebuildPagination(data.result.page, data.result.total_pages);
                            }
                        })
                        .catch(function() { showLoading(false); });
                    }

                    function debouncedSearch() {
                        if (searchTimer) clearTimeout(searchTimer);
                        currentPage = 1;
                        searchTimer = setTimeout(refreshData, 300);
                    }

                    function goToPage(pg) {
                        currentPage = pg;
                        refreshData();
                        window.scrollTo({ top: 0, behavior: 'smooth' });
                    }

                    function rebuildPagination(page, totalPages) {
                        var nav = document.getElementById('fi_pagination');
                        if (!nav) return;
                        if (totalPages &lt;= 1) { nav.innerHTML = ''; return; }

                        var html = '&lt;ul class="pagination pagination-sm justify-content-center">';
                        html += '&lt;li class="page-item' + (page &lt;= 1 ? ' disabled' : '') + '">'
                             + '&lt;a class="page-link" href="#" data-page="' + (page - 1) + '">&amp;lt;&lt;/a>&lt;/li>';

                        for (var pg = 1; pg &lt;= totalPages; pg++) {
                            if (pg &lt;= 3 || Math.abs(pg - page) &lt;= 1 || pg === totalPages) {
                                html += '&lt;li class="page-item' + (pg === page ? ' active' : '') + '">'
                                     + '&lt;a class="page-link" href="#" data-page="' + pg + '">' + pg + '&lt;/a>&lt;/li>';
                            } else if (pg === 4 &amp;&amp; page > 5) {
                                html += '&lt;li class="page-item disabled">&lt;span class="page-link">...&lt;/span>&lt;/li>';
                            } else if (pg === totalPages - 1 &amp;&amp; page &lt; totalPages - 3) {
                                html += '&lt;li class="page-item disabled">&lt;span class="page-link">...&lt;/span>&lt;/li>';
                            }
                        }

                        html += '&lt;li class="page-item' + (page >= totalPages ? ' disabled' : '') + '">'
                             + '&lt;a class="page-link" href="#" data-page="' + (page + 1) + '">&amp;gt;&lt;/a>&lt;/li>';
                        html += '&lt;/ul>';
                        nav.innerHTML = html;

                        nav.querySelectorAll('a.page-link[data-page]').forEach(function(a) {
                            a.addEventListener('click', function(e) {
                                e.preventDefault();
                                var pg = parseInt(this.getAttribute('data-page'));
                                if (pg >= 1 &amp;&amp; pg &lt;= totalPages) goToPage(pg);
                            });
                        });
                    }

                    function updateCount(shown, total) {
                        var el = document.getElementById('fi_count_text');
                        if (el) el.textContent = 'Showing ' + shown + ' of ' + total + ' products';
                    }

                    function rebuildTable(products) {
                        var tbody = document.getElementById('fi_table_body');
                        if (!tbody) return;
                        var html = '';
                        products.forEach(function(p) {
                            var isRemoteOnly = p.remote_only || false;
                            var availClass = p.available_qty &lt;= 0 ? 'text-danger' : 'text-success';
                            var marginClass = p.margin_pct > 0 ? 'bg-success' : 'bg-secondary';
                            var remoteQty = p.remote_qty || 0;
                            var totalQty = p.total_qty || p.qty_on_hand;

                            var actionHtml = '';
                            if (!isRemoteOnly) {
                                if (p.available_qty > 0) {
                                    actionHtml += '&lt;button class="btn btn-sm btn-outline-primary fi-book-btn" data-id="' + p.id + '" data-name="' + escHtml(p.name) + '">Book&lt;/button>';
                                }
                                if (hasSync &amp;&amp; remoteQty > 0 &amp;&amp; p.id > 0) {
                                    actionHtml += '&lt;button class="btn btn-sm btn-outline-secondary fi-transfer-btn" data-id="' + p.id + '" data-name="' + escHtml(p.name) + '" data-remote-qty="' + remoteQty + '">&lt;i class="fa fa-exchange">&lt;/i>&lt;/button>';
                                }
                                if (!actionHtml) actionHtml = '&lt;span class="text-muted small">--&lt;/span>';
                                actionHtml = '&lt;div class="btn-group btn-group-sm">' + actionHtml + '&lt;/div>';
                            } else {
                                actionHtml = '&lt;span class="text-muted small">' + escHtml(p.config_name || '') + '&lt;/span>';
                            }

                            var remoteCol = '';
                            var totalCol = '';
                            if (hasSync) {
                                var whTooltip = (p.remote_warehouses || []).map(function(w) { return w.warehouse + ': ' + w.qty; }).join(', ');
                                remoteCol = remoteQty > 0
                                    ? '&lt;span class="badge text-white fi-remote-badge" style="background:#6f42c1; cursor:pointer;" title="' + escHtml(whTooltip) + '">' + remoteQty + '&lt;/span>'
                                    : '&lt;span class="text-muted">0&lt;/span>';
                                totalCol = '&lt;strong>' + totalQty + '&lt;/strong>';
                            }

                            var trClass = isRemoteOnly ? ' class="table-light fst-italic"' : '';
                            var nameCell = isRemoteOnly
                                ? '&lt;span class="badge bg-secondary me-1">Remote&lt;/span>' + escHtml(p.name)
                                : '&lt;strong>' + escHtml(p.name) + '&lt;/strong>';

                            html += '&lt;tr' + trClass + ' data-id="' + p.id + '">'
                                + '&lt;td class="fi-col-product">' + nameCell + '&lt;/td>'
                                + '&lt;td class="fi-col-sku text-muted">' + escHtml(p.default_code) + '&lt;/td>'
                                + '&lt;td class="fi-col-cat">' + escHtml(p.category) + '&lt;/td>'
                                + '&lt;td class="fi-col-num">' + p.qty_on_hand + '&lt;/td>'
                                + '&lt;td class="fi-col-num">&lt;span class="fw-bold ' + availClass + '">' + p.available_qty + '&lt;/span>&lt;/td>'
                                + (hasSync ? '&lt;td class="fi-col-num">' + remoteCol + '&lt;/td>' : '')
                                + (hasSync ? '&lt;td class="fi-col-num">' + totalCol + '&lt;/td>' : '')
                                + '&lt;td class="fi-col-num">' + (p.booked_qty > 0 ? '&lt;span class="badge bg-warning text-dark">' + p.booked_qty + '&lt;/span>' : '') + '&lt;/td>'
                                + '&lt;td class="fi-col-num">' + (p.shadow_qty > 0 ? '&lt;span class="badge bg-info">' + p.shadow_qty + '&lt;/span>' : '') + '&lt;/td>'
                                + '&lt;td class="fi-col-price">$' + p.sale_price.toFixed(2) + '&lt;/td>'
                                + '&lt;td class="fi-col-num">&lt;span class="badge ' + marginClass + '">' + p.margin_pct.toFixed(1) + '%&lt;/span>&lt;/td>'
                                + '&lt;td class="fi-col-action">' + actionHtml + '&lt;/td>'
                                + '&lt;/tr>';
                        });
                        tbody.innerHTML = html;
                        bindBookButtons();
                        bindTransferButtons();
                    }

                    function rebuildMobileCards(products) {
                        var container = document.getElementById('fi_mobile_cards');
                        if (!container) return;
                        var html = '';
                        products.forEach(function(p) {
                            if (p.remote_only) return;
                            var borderColor = p.booked_qty > 0 ? '#ffc107' : (p.available_qty > 0 ? '#198754' : '#dc3545');
                            var marginClass = p.margin_pct > 0 ? 'bg-success' : 'bg-secondary';
                            var remoteQty = p.remote_qty || 0;
                            var availClass = p.available_qty &lt;= 0 ? 'text-danger' : '';

                            var remoteMobile = '';
                            if (hasSync) {
                                remoteMobile = '&lt;div class="col">'
                                    + '&lt;div class="fw-bold" style="color:#6f42c1;">' + remoteQty + '&lt;/div>'
                                    + '&lt;div class="text-muted" style="font-size:.7rem;">Remote&lt;/div>'
                                    + '&lt;/div>';
                            }

                            var btns = '';
                            if (p.available_qty > 0) {
                                btns += '&lt;button class="btn btn-sm btn-outline-primary fi-book-btn" data-id="' + p.id + '" data-name="' + escHtml(p.name) + '">Book&lt;/button>';
                            }
                            if (hasSync &amp;&amp; remoteQty > 0 &amp;&amp; p.id > 0) {
                                btns += '&lt;button class="btn btn-sm btn-outline-secondary fi-transfer-btn" data-id="' + p.id + '" data-name="' + escHtml(p.name) + '" data-remote-qty="' + remoteQty + '">&lt;i class="fa fa-exchange">&lt;/i> Transfer&lt;/button>';
                            }

                            var colClass = hasSync ? 'col' : 'col-3';
                            var rowClass = hasSync ? 'row g-1 mt-2 text-center row-cols-5' : 'row g-1 mt-2 text-center';

                            html += '&lt;div class="card mb-2 fi-card" data-id="' + p.id + '" style="border-left: 4px solid ' + borderColor + ';">'
                                + '&lt;div class="card-body py-2 px-3">'
                                + '&lt;div class="d-flex justify-content-between align-items-start">'
                                + '&lt;div style="max-width:65%;">'
                                + '&lt;div class="fw-bold text-truncate">' + escHtml(p.name) + '&lt;/div>'
                                + '&lt;small class="text-muted">' + escHtml(p.default_code) + (p.category ? ' | ' + escHtml(p.category) : '') + '&lt;/small>'
                                + '&lt;/div>'
                                + '&lt;div class="text-end">'
                                + '&lt;div class="fw-bold">$' + p.sale_price.toFixed(2) + '&lt;/div>'
                                + '&lt;span class="badge ' + marginClass + ' small">' + p.margin_pct.toFixed(1) + '%&lt;/span>'
                                + '&lt;/div>'
                                + '&lt;/div>'
                                + '&lt;div class="' + rowClass + '" style="font-size:.85rem;">'
                                + '&lt;div class="' + colClass + '">&lt;div class="fw-bold">' + p.qty_on_hand + '&lt;/div>&lt;div class="text-muted" style="font-size:.7rem;">Local&lt;/div>&lt;/div>'
                                + '&lt;div class="' + colClass + '">&lt;div class="fw-bold ' + availClass + '">' + p.available_qty + '&lt;/div>&lt;div class="text-muted" style="font-size:.7rem;">Avail&lt;/div>&lt;/div>'
                                + remoteMobile
                                + '&lt;div class="' + colClass + '">&lt;div class="fw-bold">' + p.booked_qty + '&lt;/div>&lt;div class="text-muted" style="font-size:.7rem;">Booked&lt;/div>&lt;/div>'
                                + '&lt;div class="' + colClass + '">&lt;div class="fw-bold">' + p.shadow_qty + '&lt;/div>&lt;div class="text-muted" style="font-size:.7rem;">Incoming&lt;/div>&lt;/div>'
                                + '&lt;/div>'
                                + (btns ? '&lt;div class="mt-2 text-end">&lt;div class="btn-group btn-group-sm">' + btns + '&lt;/div>&lt;/div>' : '')
                                + '&lt;/div>&lt;/div>';
                        });
                        container.innerHTML = html;
                        bindBookButtons();
                        bindTransferButtons();
                    }

                    function escHtml(s) {
                        if (!s) return '';
                        return s.replace(/&amp;/g, '&amp;amp;').replace(/&lt;/g, '&amp;lt;').replace(/>/g, '&amp;gt;').replace(/"/g, '&amp;quot;');
                    }

                    /* ── Booking ── */

                    function bookProduct(productId, productName) {
                        if (!confirm('Book "' + productName + '" for 24 hours?')) return;

                        fetch('/my/inventory/book', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({
                                jsonrpc: '2.0',
                                method: 'call',
                                params: {product_id: productId, quantity: 1}
                            })
                        })
                        .then(function(r) { return r.json(); })
                        .then(function(data) {
                            var res = data.result || {};
                            if (res.success) {
                                alert('Product booked! Expires at ' + res.expires_at);
                                refreshData();
                            } else {
                                alert(res.error || 'Booking failed');
                            }
                        })
                        .catch(function() { alert('Network error'); });
                    }

                    function bindBookButtons() {
                        document.querySelectorAll('.fi-book-btn').forEach(function(btn) {
                            btn.addEventListener('click', function(e) {
                                e.preventDefault();
                                bookProduct(
                                    parseInt(this.getAttribute('data-id')),
                                    this.getAttribute('data-name') || ''
                                );
                            });
                        });
                    }

                    /* ── Transfer ── */

                    var currentTransferProductId = null;

                    function bindTransferButtons() {
                        document.querySelectorAll('.fi-transfer-btn').forEach(function(btn) {
                            btn.addEventListener('click', function(e) {
                                e.preventDefault();
                                var pid = parseInt(this.getAttribute('data-id'));
                                var pname = this.getAttribute('data-name') || '';
                                var remoteQty = parseFloat(this.getAttribute('data-remote-qty') || '0');
                                openTransferModal(pid, pname, remoteQty);
                            });
                        });
                    }

                    function openTransferModal(productId, productName, remoteQty) {
                        currentTransferProductId = productId;
                        document.getElementById('fi_transfer_product_name').textContent = productName;
                        document.getElementById('fi_transfer_remote_qty').textContent = remoteQty;
                        document.getElementById('fi_transfer_qty').value = 1;
                        document.getElementById('fi_transfer_qty').max = remoteQty;
                        document.getElementById('fi_transfer_result').classList.add('d-none');
                        document.getElementById('fi_transfer_success').classList.add('d-none');
                        document.getElementById('fi_transfer_error').classList.add('d-none');
                        document.getElementById('fi_transfer_confirm_btn').disabled = false;

                        var modal = new bootstrap.Modal(document.getElementById('fi_transfer_modal'));
                        modal.show();
                    }

                    function executeTransfer() {
                        if (!currentTransferProductId) return;
                        var qty = parseFloat(document.getElementById('fi_transfer_qty').value) || 1;
                        var btn = document.getElementById('fi_transfer_confirm_btn');
                        var spinner = document.getElementById('fi_transfer_spinner');

                        btn.disabled = true;
                        spinner.classList.remove('d-none');

                        fetch('/my/inventory/transfer', {
                            method: 'POST',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({
                                jsonrpc: '2.0',
                                method: 'call',
                                params: {
                                    product_id: currentTransferProductId,
                                    quantity: qty
                                }
                            })
                        })
                        .then(function(r) { return r.json(); })
                        .then(function(data) {
                            spinner.classList.add('d-none');
                            document.getElementById('fi_transfer_result').classList.remove('d-none');
                            var res = data.result || {};
                            if (res.success) {
                                var msg = 'Transfer initiated!';
                                if (res.local_po) msg += ' Local PO: ' + res.local_po;
                                if (res.remote_so) msg += ' | Remote SO: ' + res.remote_so;
                                var successEl = document.getElementById('fi_transfer_success');
                                successEl.textContent = msg;
                                successEl.classList.remove('d-none');
                                refreshData();
                            } else {
                                var errorEl = document.getElementById('fi_transfer_error');
                                errorEl.textContent = res.error || 'Transfer failed';
                                errorEl.classList.remove('d-none');
                                btn.disabled = false;
                            }
                        })
                        .catch(function() {
                            spinner.classList.add('d-none');
                            btn.disabled = false;
                            alert('Network error');
                        });
                    }

                    /* ── Category Search ── */

                    var catSearchTimer = null;

                    function setupCategorySearch() {
                        var input = document.getElementById('fi_category_search');
                        var hidden = document.getElementById('fi_category_filter');
                        var dropdown = document.getElementById('fi_category_dropdown');
                        if (!input || !dropdown) return;

                        input.addEventListener('input', function() {
                            if (catSearchTimer) clearTimeout(catSearchTimer);
                            var q = input.value.trim();
                            if (q.length === 0) {
                                hidden.value = '';
                                dropdown.classList.add('d-none');
                                refreshData(true);
                                return;
                            }
                            catSearchTimer = setTimeout(function() {
                                fetch('/my/inventory/categories', {
                                    method: 'POST',
                                    headers: {'Content-Type': 'application/json'},
                                    body: JSON.stringify({
                                        jsonrpc: '2.0', method: 'call',
                                        params: { search: q }
                                    })
                                })
                                .then(function(r) { return r.json(); })
                                .then(function(data) {
                                    var cats = data.result || [];
                                    var html = '';
                                    if (cats.length === 0) {
                                        html = '&lt;div class="px-3 py-2 text-muted small">No categories found&lt;/div>';
                                    }
                                    cats.forEach(function(c) {
                                        html += '&lt;div class="px-3 py-2 fi-cat-option" style="cursor:pointer;" data-id="' + c.id + '" data-name="' + escHtml(c.name) + '">'
                                            + escHtml(c.name) + '&lt;/div>';
                                    });
                                    dropdown.innerHTML = html;
                                    dropdown.classList.remove('d-none');
                                    dropdown.querySelectorAll('.fi-cat-option').forEach(function(opt) {
                                        opt.addEventListener('click', function() {
                                            hidden.value = this.getAttribute('data-id');
                                            input.value = this.getAttribute('data-name');
                                            dropdown.classList.add('d-none');
                                            refreshData(true);
                                        });
                                        opt.addEventListener('mouseenter', function() {
                                            this.style.background = '#e9ecef';
                                        });
                                        opt.addEventListener('mouseleave', function() {
                                            this.style.background = '';
                                        });
                                    });
                                });
                            }, 250);
                        });

                        input.addEventListener('focus', function() {
                            if (input.value.trim()) input.dispatchEvent(new Event('input'));
                        });

                        document.addEventListener('click', function(e) {
                            if (!input.contains(e.target) &amp;&amp; !dropdown.contains(e.target)) {
                                dropdown.classList.add('d-none');
                            }
                        });
                    }

                    /* ── Init ── */

                    document.addEventListener('DOMContentLoaded', function() {
                        bindBookButtons();
                        bindTransferButtons();
                        setupCategorySearch();

                        var searchBtn = document.getElementById('fi_search_btn');
                        var searchInput = document.getElementById('fi_search');
                        var whFilter = document.getElementById('fi_warehouse_filter');
                        var transferBtn = document.getElementById('fi_transfer_confirm_btn');

                        if (searchBtn) searchBtn.addEventListener('click', function() { refreshData(true); });
                        if (searchInput) {
                            searchInput.addEventListener('input', debouncedSearch);
                            searchInput.addEventListener('keydown', function(e) {
                                if (e.key === 'Enter') { e.preventDefault(); refreshData(true); }
                            });
                        }
                        if (whFilter) whFilter.addEventListener('change', function() { refreshData(true); });
                        if (transferBtn) transferBtn.addEventListener('click', executeTransfer);

                        rebuildPagination(<t t-esc="page"/>, <t t-esc="total_pages"/>);
                        timer = setInterval(refreshData, refreshInterval);
                        updateTimestamp();
                    });
                })();
            </script>

        </t>
    </template>

</odoo>
