<style>
  body { font-family: Arial, sans-serif; font-size: 13px; background: #f4f6f8; margin: 0; padding: 0; }

  .top-bar {
    background: #9c4893;
    color: #fff;
    padding: 12px 20px;
    display: flex;
    align-items: center;
    gap: 20px;
  }
  .top-bar h1 { font-size: 18px; margin: 0; letter-spacing: 1px; }
  .top-bar button {
    margin-left: auto;
    background: #00d4ff;
    color: #000;
    border: none;
    padding: 7px 18px;
    font-weight: bold;
    cursor: pointer;
    border-radius: 3px;
  }

  .filter-bar {
    background: #fff;
    border-bottom: 1px solid #ddd;
    padding: 10px 20px;
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
  }
  .filter-bar label { font-weight: bold; font-size: 12px; }
  .filter-bar select, .filter-bar input {
    border: 1px solid #ccc;
    padding: 5px 10px;
    border-radius: 3px;
    font-size: 12px;
    min-width: 150px;
  }
  .filter-bar button {
    padding: 5px 16px;
    border: none;
    border-radius: 3px;
    cursor: pointer;
    font-weight: bold;
    font-size: 12px;
  }
  .btn-apply { background: #00D100; color: #fff; }
  .btn-clear { background: #eee; color: #333; }

  .table-wrap { padding: 16px 20px; overflow-x: auto; }

  table {
    width: 100%;
    border-collapse: collapse;
    background: #fff;
    box-shadow: 0 1px 4px rgba(0,0,0,.08);
  }
  thead th {
    background: #913f88;
    color: #fff;
    padding: 10px 12px;
    text-align: left;
    font-size: 12px;
    letter-spacing: .5px;
    white-space: nowrap;
    border: 1px solid #0d0d20;
  }
  tbody td {
    padding: 9px 12px;
    border: 1px solid #e0e0e0;
    vertical-align: top;
    color: #333;
  }
  tbody tr:nth-child(even) { background: #f9f9fb; }
  tbody tr:hover { background: #eef4ff; }

  .tl {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 12px;
    font-weight: bold;
    font-size: 11px;
    white-space: nowrap;
    margin-top: 4px;
  }
  .tl-red    { background: #ffe5e5; color: #c0392b; border: 1px solid #e74c3c; }
  .tl-yellow { background: #fff8e1; color: #b7770d; border: 1px solid #f5a623; }
  .tl-green  { background: #e8f8f0; color: #1a7a4a; border: 1px solid #27ae60; }

  .wh {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 3px;
    font-size: 11px;
    font-weight: bold;
    background: #e8f0fe;
    color: #1a56db;
    border: 1px solid #b3c7f9;
  }

  /* Cell badges */
  .cell-vac    { background:#e0f7fa; color:#00796b; border:1px solid #80cbc4; padding:2px 7px; border-radius:3px; font-size:11px; font-weight:bold; }
  .cell-cnc    { background:#fff3e0; color:#e65100; border:1px solid #ffcc80; padding:2px 7px; border-radius:3px; font-size:11px; font-weight:bold; }
  .cell-pu     { background:#e3f2fd; color:#0d47a1; border:1px solid #90caf9; padding:2px 7px; border-radius:3px; font-size:11px; font-weight:bold; }
  .cell-assypu { background:#fce4ec; color:#880e4f; border:1px solid #f48fb1; padding:2px 7px; border-radius:3px; font-size:11px; font-weight:bold; }
  .cell-assy   { background:#e8eaf6; color:#283593; border:1px solid #9fa8da; padding:2px 7px; border-radius:3px; font-size:11px; font-weight:bold; }
  .cell-mfg    { background:#f3e5f5; color:#6a1b9a; border:1px solid #ce93d8; padding:2px 7px; border-radius:3px; font-size:11px; font-weight:bold; }

  .bom-type {
    background: #eee;
    color: #555;
    font-size: 10px;
    padding: 1px 4px;
    border-radius: 2px;
    margin-right: 4px;
  }

  .pick-cell { text-align: center; width: 32px; }
  .pick-box  { width: 16px; height: 16px; cursor: pointer; }

  tr.picking-out { opacity: 0.35; transition: opacity .2s ease; }
  tr.row-picked  { background: #f3f3f3 !important; color: #999; }
  tr.row-picked td { color: #999; }

  .picked-tag {
    background: #e0e0e0;
    color: #666;
    font-size: 10px;
    font-weight: bold;
    padding: 1px 6px;
    border-radius: 8px;
    margin-left: 6px;
  }

  .state-msg td {
    text-align: center;
    padding: 40px;
    color: #888;
    font-style: italic;
  }
</style>

<div class="top-bar">
  <h1>KITTING LIST</h1>
  <button onclick="loadKitting()">&#8635; Refresh</button>
</div>

<div class="filter-bar">
  <label>Warehouse</label>
  <select id="f-warehouse" onchange="applyFilters()">
    <option value="">All</option>
  </select>

  <label>Cell</label>
  <select id="f-cell" onchange="applyFilters()">
    <option value="">All</option>
    <option value="VAC">VAC</option>
    <option value="CNC">CNC</option>
    <option value="PU">PU</option>
    <option value="ASSY-PU">ASSY-PU</option>
    <option value="ASSY">ASSY</option>
  </select>

  <label>Traffic</label>
  <select id="f-traffic" onchange="applyFilters()">
    <option value="">All</option>
    <option value="red">🔴 Critical (&lt;1h)</option>
    <option value="yellow">🟡 Warning (1–3h)</option>
    <option value="green">🟢 OK (&gt;3h)</option>
  </select>

  <label>Status</label>
  <select id="f-status" onchange="applyFilters()">
    <option value="unpicked" selected>Unpicked (default)</option>
    <option value="picked">Picked only</option>
    <option value="all">All</option>
  </select>

  <label>Search</label>
  <input type="text" id="f-search" placeholder="WO / Part / Product…" oninput="applyFilters()"/>

  <button class="btn-apply" onclick="applyFilters()">Apply</button>
  <button class="btn-clear" onclick="clearFilters()">Clear</button>
</div>

<div class="table-wrap">
  <table>
    <thead>
      <tr>
        <th>Pick</th>
        <th>Work Order</th>
        <th>Cell</th>
        <th>Part / Product</th>
        <th class="hide">Qty</th>
        <th>Tooling</th>
        <th>BOM Component</th>
        <th>Qty</th>
        <th>Warehouse Location</th>
        <th>Due Time</th>
      </tr>
    </thead>
    <tbody id="kitting-body">
      <tr class="state-msg"><td colspan="10">Loading&hellip;</td></tr>
    </tbody>
  </table>
</div>

<script>
var allRows = [];
var url     = site_url + '/modules/kitting/index.php?page=ajax_kitting_list&action=get_work_orders';
var pickUrl = site_url + '/modules/kitting/index.php?page=ajax_kitting_list&action=toggle_pick';

/* ── Load data from server ── */
function loadKitting() {
    document.getElementById('kitting-body').innerHTML = '<tr class="state-msg"><td colspan="10">Loading&hellip;</td></tr>';

    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onload = function () {
        if (xhr.status === 200) {
            try {
                var data = JSON.parse(xhr.responseText);
                allRows = data.rows || [];
                populateWarehouseFilter(data.all_locations || []);
                applyFilters();
            } catch (e) {
                document.getElementById('kitting-body').innerHTML = '<tr class="state-msg"><td colspan="10">Invalid response from server.</td></tr>';
            }
        } else {
            document.getElementById('kitting-body').innerHTML = '<tr class="state-msg"><td colspan="10">Error loading data (HTTP ' + xhr.status + ').</td></tr>';
        }
    };
    xhr.onerror = function () {
        document.getElementById('kitting-body').innerHTML = '<tr class="state-msg"><td colspan="10">Request failed.</td></tr>';
    };
    xhr.send();
}
function populateWarehouseFilter(locations) {
    var select  = document.getElementById('f-warehouse');
    var current = select.value;

    select.innerHTML = '<option value="">All</option>';

    locations.sort();

    for (var i = 0; i < locations.length; i++) {
        var loc = locations[i];

        if (!loc || loc === 'N/A') continue;

        var opt = document.createElement('option');
        opt.value = loc;
        opt.textContent = loc;

        if (loc === current) opt.selected = true;

        select.appendChild(opt);
    }
}

/* ── Traffic light helpers ── */
function trafficLight(endDate) {
    var diff = (new Date(endDate) - new Date()) / 60000;
    if (diff < 0)   return '<span class="tl tl-red">🔴 OVERDUE</span>';
    if (diff < 60)  return '<span class="tl tl-red">🔴 '    + Math.round(diff) + 'm left</span>';
    if (diff < 180) return '<span class="tl tl-yellow">🟡 ' + Math.floor(diff / 60) + 'h ' + Math.round(diff % 60) + 'm left</span>';
    return             '<span class="tl tl-green">🟢 '      + Math.floor(diff / 60) + 'h ' + Math.round(diff % 60) + 'm left</span>';
}

function trafficClass(endDate) {
    var diff = (new Date(endDate) - new Date()) / 60000;
    if (diff < 60)  return 'red';
    if (diff < 180) return 'yellow';
    return 'green';
}

/* ── Formatting helpers ── */
function fmtDate(d) {
    if (!d) return '&mdash;';
    return new Date(d).toLocaleString('en-GB', {
        day: '2-digit', month: 'short', year: 'numeric',
        hour: '2-digit', minute: '2-digit'
    });
}

function esc(v) {
    return String(v == null ? '' : v)
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');
}

function cellBadge(cell) {
    var c   = (cell || '').toUpperCase();
    var cls;
    if      (c === 'VAC')     cls = 'cell-vac';
    else if (c === 'CNC')     cls = 'cell-cnc';
    else if (c === 'PU')      cls = 'cell-pu';
    else if (c === 'ASSY-PU') cls = 'cell-assypu';
    else if (c === 'ASSY')    cls = 'cell-assy';
    else                      cls = 'cell-mfg';
    return '<span class="' + cls + '">' + (c || '&mdash;') + '</span>';
}

function renderBomName(item) {
    if (!item) return '&mdash;';
    return '<span class="bom-type">' + esc((item.type || 'COMP').toUpperCase()) + '</span>'
         + esc(item.sub_part_name || '&mdash;')
         + (item.picked ? ' <span class="picked-tag">PICKED</span>' : '');
}

function renderBomQty(item) {
    if (!item) return '&mdash;';
    return '&times;' + (item.quantity_required || 1);
}

function renderTooling(r) {
    var lines = [];
    if (r.tool_location)             lines.push('🔧 ' + esc(r.tool_location));
    if (r.checking_fixture_location) lines.push('📐 ' + esc(r.checking_fixture_location));
    if (r.cnc_program_no)            lines.push('💾 ' + esc(r.cnc_program_no));
    return lines.length ? lines.join('<br>') : '&mdash;';
}

/* ── Render table rows: one fully self-contained <tr> per BOM
      component — WO / Cell / Part / Tooling / Warehouse / Due Time are
      repeated on every row (no rowspan merging).
      `status` controls which components are shown: unpicked / picked / all. ── */
function renderTable(rows, status) {
    var tbody = document.getElementById('kitting-body');

    var html = '';
    var totalRendered = 0;

    for (var i = 0; i < rows.length; i++) {
        var r = rows[i];
        var allItems = r.bom_items || [];

        // filter this WO's components by the selected status
        var items = allItems.filter(function (it) {
            if (status === 'picked')   return !!it.picked;
            if (status === 'unpicked') return !it.picked;
            return true; // 'all'
        });

        if (items.length === 0) {
            // Only show a "no components" placeholder row when the WO
            // genuinely has no BOM data at all, and we're not exclusively
            // looking at "Picked" (which wouldn't apply here anyway).
            if (allItems.length === 0 && status !== 'picked') {
                items = [null];
            } else {
                continue; // nothing matches this filter for this WO — skip it
            }
        }

        var woCell = '<strong>#' + esc(r.work_order_id || '&mdash;') + '</strong><br>' + esc(r.work_order_name || r.product_name || '&mdash;');
        var cellCell = cellBadge(r.cell);
        var partCell = '<strong>' + esc(r.part_number || '&mdash;') + '</strong><br>' + esc(r.product_description || r.product_name || '&mdash;');
        var qtyCell = esc(r.quantity || '&mdash;');
        var toolCell = renderTooling(r);
        var whCell = '<span class="wh">' + esc(r.warehouse_location || '&mdash;') + '</span>';
        var dueCell = fmtDate(r.end_date) + '<br>' + trafficLight(r.end_date);

        for (var j = 0; j < items.length; j++) {
            var item   = items[j];
            var rowCls = item && item.picked ? ' class="row-picked"' : '';

            html += '<tr' + rowCls + '>';

            // Pick checkbox — one per BOM component row
            if (item) {
                html += '<td class="pick-cell">'
                      +   '<input type="checkbox" class="pick-box" '
                      +     (item.picked ? 'checked ' : '')
                      +     'data-schedule="' + esc(r.schedule_id) + '" '
                      +     'data-cell="' + esc(r.cell) + '" '
                      +     'data-bomkey="' + esc(item.bom_key) + '" '
                      +     'onchange="pickItem(this)">'
                      + '</td>';
            } else {
                html += '<td class="pick-cell">&mdash;</td>';
            }

            html += '<td>' + woCell + '</td>';
            html += '<td>' + cellCell + '</td>';
            html += '<td>' + partCell + '</td>';
            html += '<td class="hide">' + qtyCell + '</td>';
            html += '<td>' + toolCell + '</td>';
            html += '<td>' + renderBomName(item) + '</td>';
            html += '<td>' + renderBomQty(item) + '</td>';
            html += '<td>' + whCell + '</td>';
            html += '<td>' + dueCell + '</td>';

            html += '</tr>';
            totalRendered++;
        }
    }

    tbody.innerHTML = totalRendered ? html : '<tr class="state-msg"><td colspan="10">No records found.</td></tr>';
}

/* ── Checkbox click: persist pick/un-pick, then flip the flag in the
      data model and re-render — dynamic, no page reload. Ticking hides
      it under the default "Unpicked" filter; unticking (from the
      "Picked"/"All" views) brings it back. ── */
function pickItem(checkbox) {
    var scheduleId  = checkbox.getAttribute('data-schedule');
    var cell        = checkbox.getAttribute('data-cell');
    var bomKey      = checkbox.getAttribute('data-bomkey');
    var newPicked   = checkbox.checked ? 1 : 0;
    var row         = checkbox.closest('tr');

    checkbox.disabled = true;
    if (row && newPicked) row.classList.add('picking-out');

    var xhr = new XMLHttpRequest();
    xhr.open('POST', pickUrl, true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onload = function () {
        var ok = false;
        try {
            var resp = JSON.parse(xhr.responseText);
            ok = xhr.status === 200 && resp && resp.success;
            if (!ok) console.error('Pick failed:', resp && resp.error);
        } catch (e) {
            console.error('Invalid response saving pick.');
        }

        if (ok) {
            setBomItemPicked(scheduleId, cell, bomKey, !!newPicked);
        } else {
            checkbox.checked  = !newPicked;
            checkbox.disabled = false;
            if (row) row.classList.remove('picking-out');
            alert('Could not save that change — please try again.');
        }
    };
    xhr.onerror = function () {
        checkbox.checked  = !newPicked;
        checkbox.disabled = false;
        if (row) row.classList.remove('picking-out');
        alert('Request failed — please try again.');
    };
    xhr.send(
        'schedule_id=' + encodeURIComponent(scheduleId) +
        '&cell=' + encodeURIComponent(cell) +
        '&bom_key=' + encodeURIComponent(bomKey) +
        '&picked=' + newPicked
    );
}

function setBomItemPicked(scheduleId, cell, bomKey, picked) {
    for (var i = 0; i < allRows.length; i++) {
        var r = allRows[i];
        if (String(r.schedule_id) === String(scheduleId) && r.cell === cell) {
            var items = r.bom_items || [];
            for (var j = 0; j < items.length; j++) {
                if (items[j].bom_key === bomKey) items[j].picked = picked;
            }
        }
    }
    applyFilters(); // re-render from the updated data model
}

/* ── Apply all filters ── */
function applyFilters() {
    var wh      = document.getElementById('f-warehouse').value;
    var cell    = document.getElementById('f-cell').value.toUpperCase();
    var traffic = document.getElementById('f-traffic').value;
    var search  = document.getElementById('f-search').value.toLowerCase();
    var status  = document.getElementById('f-status').value; // unpicked | picked | all

    var filtered = allRows.filter(function (r) {
        var loc = (r.warehouse_location || '');
        var ce  = (r.cell || '').toUpperCase();
        var nm  = ((r.work_order_id    || '') + ' ' +
                   (r.work_order_name  || '') + ' ' +
                   (r.product_name     || '') + ' ' +
                   (r.part_number      || '')).toLowerCase();

        if (wh      && loc !== wh)                        return false;
        if (cell    && ce  !== cell)                      return false;
        if (search  && nm.indexOf(search) === -1)         return false;
        if (traffic && trafficClass(r.end_date) !== traffic) return false;
        return true;
    });

    filtered.sort(function (a, b) { return new Date(a.end_date) - new Date(b.end_date); });

    renderTable(filtered, status);
}

/* ── Clear all filters ── */
function clearFilters() {
    document.getElementById('f-warehouse').value = '';
    document.getElementById('f-cell').value      = '';
    document.getElementById('f-traffic').value   = '';
    document.getElementById('f-search').value    = '';
    document.getElementById('f-status').value    = 'unpicked';
    applyFilters();
}

/* ── Init + auto-refresh every 5 minutes ── */
loadKitting();
setInterval(loadKitting, 5 * 60 * 1000);
</script>