<?php
require __DIR__ . '/inc/app.php';
require_login();
$all = !empty($_GET['all']);
$admin = is_admin();
// "Not restocking": product stays visible while there is stock, but never asks to be reordered; hidden once it is at zero.
try { db()->exec('ALTER TABLE products ADD COLUMN IF NOT EXISTS no_reorder TINYINT(1) NOT NULL DEFAULT 0'); } catch (Throwable $e) {}

$rows = db()->query("SELECT p.*, s.name AS supplier, COALESCE(m.stock, 0) AS stock, COALESCE(o.on_order, 0) AS on_order, COALESCE(o.on_order_value, 0) AS on_order_value
  FROM products p
  LEFT JOIN suppliers s ON s.id = p.supplier_id
  LEFT JOIN (SELECT product_id, SUM(qty) AS stock FROM movements GROUP BY product_id) m ON m.product_id = p.id
  LEFT JOIN (SELECT l.product_id, SUM(l.qty) AS on_order, SUM(l.qty * l.unit_price) AS on_order_value FROM order_lines l JOIN orders o ON o.id = l.order_id
             WHERE o.status IN ('open','ready') GROUP BY l.product_id) o ON o.product_id = p.id
  WHERE " . product_scope() . ($all ? '' : ' AND p.active = 1') . " ORDER BY p.model, p.color")->fetchAll();
// Already in shipments that are not picked up yet (status To ship): still at the supplier, but no longer free
$insh = [];
foreach (db()->query("SELECT l.product_id, SUM(l.qty) AS q, GROUP_CONCAT(DISTINCT CONCAT(s.country, '-', s.fba_id) ORDER BY s.id SEPARATOR ', ') AS refs
    FROM shipment_lines l JOIN shipments s ON s.id = l.shipment_id WHERE s.status = 'new' GROUP BY l.product_id") as $x) $insh[(int)$x['product_id']] = $x;
$hiddenNR = 0;
if (!$all) $rows = array_values(array_filter($rows, function ($r) use (&$hiddenNR) {
    if (!empty($r['no_reorder']) && (int)$r['stock'] == 0 && (int)$r['on_order'] == 0) { $hiddenNR++; return false; } return true; }));
// Average unit cost incl. freight per product, over all shipments with a known freight cost (freight spread by weight).
$landed = [];
if ($admin) {
    $lines = db()->query("SELECT l.shipment_id, l.product_id, l.qty,
        (CASE WHEN l.cartons > 0 THEN l.cartons ELSE l.qty / NULLIF(p.pcs_per_carton, 0) END) * COALESCE(p.carton_kg, 0) AS kg,
        COALESCE(NULLIF((SELECT SUM(c.unit_price * c.qty) FROM freight_costs c WHERE c.shipment_id = l.shipment_id), 0), f.quote_amount) AS freight
      FROM shipment_lines l JOIN shipments s ON s.id = l.shipment_id JOIN products p ON p.id = l.product_id
      LEFT JOIN freight f ON f.shipment_id = l.shipment_id
      WHERE s.status <> 'cancelled'")->fetchAll();
    $sh = [];
    foreach ($lines as $l) { $k = (int)$l['shipment_id']; $sh[$k]['kg'] = ($sh[$k]['kg'] ?? 0) + (float)$l['kg']; $sh[$k]['qty'] = ($sh[$k]['qty'] ?? 0) + (int)$l['qty']; }
    $acc = [];
    foreach ($lines as $l) {
        if ($l['freight'] === null) continue;
        $k = (int)$l['shipment_id']; $pid = (int)$l['product_id'];
        $fr = $sh[$k]['kg'] > 0 ? (float)$l['freight'] * (float)$l['kg'] / $sh[$k]['kg'] : ($sh[$k]['qty'] ? (float)$l['freight'] * (int)$l['qty'] / $sh[$k]['qty'] : 0);
        $acc[$pid]['q'] = ($acc[$pid]['q'] ?? 0) + (int)$l['qty'];
        $acc[$pid]['f'] = ($acc[$pid]['f'] ?? 0) + $fr;
    }
    foreach ($acc as $pid => $a) if ($a['q'] > 0) $landed[$pid] = $a['f'] / $a['q'];
    // Products never shipped: estimate by weight with the average freight per kg of past shipments.
    $fk = 0.0; $kk = 0.0; $seen = [];
    foreach ($lines as $l) { $k = (int)$l['shipment_id']; if ($l['freight'] === null || isset($seen[$k])) continue; $seen[$k] = 1; if ($sh[$k]['kg'] > 0) { $fk += (float)$l['freight']; $kk += $sh[$k]['kg']; } }
    $perKg = $kk > 0 ? $fk / $kk : null;
}
$est = [];
// Amazon "Recommended restock" per country (Restock Inventory report, loaded with the hourly stock sync), summed per product.
$RST_M = ['US' => 'USA', 'UK' => 'UK', 'DE' => 'Germany', 'AU' => 'Australia'];
$rst = [];
if ($admin) try {
    $smap = sku_map();
    foreach (db()->query('SELECT market, sku, qty FROM amz_restock WHERE qty > 0') as $x) {
        $pid = $smap[sku_key((string)$x['sku'])] ?? null; if (!$pid || !isset($RST_M[$x['market']])) continue;
        $rst[$pid][$x['market']] = ($rst[$pid][$x['market']] ?? 0) + (int)$x['qty'];
    }
} catch (Throwable $e) {}
$rstT = array_fill_keys(array_keys($RST_M), 0);
// status of each row and the figures for the summary at the top
$tq = 0; $tv = 0; $tvl = 0; $tov = 0; $tc = 0; $to = 0; $tin = 0; $tav = 0; $nOrder = 0; $nOn = 0; $ready = 0;
$cartons = fn($v) => rtrim(rtrim(number_format($v, 1, '.', ','), '0'), '.');
foreach ($rows as $k => $r) {
    $pid = (int)$r['id'];
    $lf = $landed[$pid] ?? null;
    if ($lf === null && $admin && $perKg !== null && (float)$r['carton_kg'] > 0 && (int)$r['pcs_per_carton'] > 0) { $lf = $perKg * (float)$r['carton_kg'] / (int)$r['pcs_per_carton']; $est[$pid] = 1; }
    $ins = (int)($insh[$pid]['q'] ?? 0); $av = (int)$r['stock'] - $ins;
    $cls = 'none';
    if ($r['active'] && empty($r['no_reorder']) && $r['min_stock'] !== null) {
        if ($av <= (int)$r['min_stock']) $cls = ($av + $r['on_order'] <= (int)$r['min_stock']) ? 'order' : 'onord'; else $cls = 'ok';
    }
    if ($cls === 'order') $nOrder++; if ($cls === 'onord') $nOn++;
    if ($av > 0) $ready += $av;
    $v = $r['stock'] * $r['price']; $vl = $r['stock'] * ((float)$r['price'] + (float)$lf);
    $tq += $r['stock']; $tv += $v; $tvl += $vl; $to += $r['on_order']; $tov += $r['on_order_value']; $tin += $ins; $tav += $av;
    $cart = $r['pcs_per_carton'] ? $r['stock'] / $r['pcs_per_carton'] : null; if ($cart !== null) $tc += $cart;
    $rows[$k] += ['_lf' => $lf, '_ins' => $ins, '_av' => $av, '_cls' => $cls, '_v' => $v, '_vl' => $vl, '_cart' => $cart];
}
page_start('Stock at the supplier’s warehouse', 'index');
$cols = 6 + ($admin ? count($RST_M) + 1 : 0);
?>
<style>
.sk { --ink:#1c1c1c; --line:#e3ded7; --soft:#faf7f3; --red:#c62828; --blue:#1565c0; --green:#1b7f3b; --rs:#eef8f1; color:var(--ink); }
html.dark .sk { --ink:#f2efe9; --line:#3a3734; --soft:#232120; --red:#ff8a80; --blue:#90caf9; --green:#81c995; --rs:#172a1e; }
.sk .top { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin:0 0 18px; }
.sk .brief { display:grid; grid-template-columns:repeat(<?= $admin ? 4 : 3 ?>, 1fr); border:1.5px solid var(--ink); border-radius:12px; overflow:hidden; margin:0 0 24px; }
.sk .brief > div { padding:14px 18px; border-right:1.5px solid var(--ink); font-size:15px; }
.sk .brief > div:last-child { border-right:0; }
.sk .brief b { display:block; font-size:32px; font-weight:800; line-height:1.1; }
.sk .brief .r b { color:var(--red); } .sk .brief .bl b { color:var(--blue); } .sk .brief .g b { color:var(--green); }
.sk table { width:100%; border-collapse:collapse; border:1px solid var(--line); font-variant-numeric:tabular-nums; }
.sk th, .sk td { border-left:1px solid var(--line); }
.sk thead th { font-size:14px; font-weight:700; text-align:right; padding:8px 10px; border-bottom:2px solid var(--ink); white-space:nowrap; vertical-align:bottom; color:var(--ink); }
.sk thead th.l { text-align:left; }
.sk thead th.rsh { text-align:center; color:var(--green); background:var(--rs); border-bottom:1px solid var(--green); }
.sk thead th.mk { text-align:center; background:var(--rs); }
.sk .mdl td { padding:14px 12px 6px; font-size:15px; font-weight:800; border-bottom:1px solid var(--line); }
.sk .row td { padding:10px 10px; border-bottom:1px solid var(--line); text-align:right; vertical-align:middle; color:var(--ink); }
.sk .row td:first-child { text-align:left; border-left:5px solid var(--line); padding-left:12px; white-space:nowrap; }
.sk .row { cursor:pointer; }
.sk .row:hover td { background:var(--soft); }
.sk .row.order td:first-child { border-left-color:var(--red); } .sk .row.onord td:first-child { border-left-color:var(--blue); } .sk .row.ok td:first-child { border-left-color:var(--green); }
.sk td.av { font-size:19px; font-weight:800; } .sk .order td.av { color:var(--red); } .sk .onord td.av { color:var(--blue); }
.sk td.rs { background:var(--rs); text-align:center; font-weight:700; color:var(--green); }
.sk .chev { display:inline-block; width:12px; transition:transform .15s; } .sk .row[aria-expanded="true"] .chev { transform:rotate(90deg); }
.sk .det td { background:var(--soft); padding:10px 22px 12px; border-bottom:1px solid var(--line); color:var(--ink); }
.sk .det dl { display:flex; gap:32px; flex-wrap:wrap; margin:0; } .sk .det dt { font-size:13px; font-weight:600; } .sk .det dd { margin:2px 0 0; font-size:16px; font-weight:700; }
.sk .note { font-size:13px; font-weight:600; }
.sk tfoot td { padding:10px; text-align:right; font-weight:800; border-top:2px solid var(--ink); }
.sk tfoot td:first-child { text-align:left; }
.sk .legend { margin-top:14px; font-size:15px; }
.sk .row:focus-visible { outline:3px solid #FF6A00; outline-offset:-3px; }
@media (max-width:820px) { .sk .brief { grid-template-columns:1fr 1fr; } .sk .brief > div { border-bottom:1.5px solid var(--ink); } }
@media (prefers-reduced-motion:reduce) { .sk .chev { transition:none; } }
</style>
<div class="sk">
<div class="top">
  <?php if ($admin): ?><a class="btn" href="stock_check.php">Check a Send to Amazon plan (PDF)</a> <a class="btn light" href="stock_xlsx.php<?= $all ? '?all=1' : '' ?>">Download Excel</a><?php endif; ?>
  <a href="<?= $all ? 'index.php' : 'index.php?all=1' ?>" style="margin-left:6px"><?= $all ? 'Hide archived products' : 'Show archived products' . ($hiddenNR ? " and $hiddenNR not restocked at zero" : '') ?></a>
</div>

<section class="brief">
  <div class="r"><b><?= $nOrder ?></b>products to order now</div>
  <div class="bl"><b><?= $nOn ?></b>low, but already on order</div>
  <div class="g"><b><?= num($ready) ?></b>pieces ready to ship</div>
  <?php if ($admin): ?><div><b><?= money($tvl) ?></b>stock value incl. freight<?= (float)$tov ? '<br>on order ' . money($tov) : '' ?></div><?php endif; ?>
</section>

<div class="wrap"><table>
<thead>
<tr><th rowspan="2" class="l">Product</th><th rowspan="2" title="In stock − In shipments: free to send or to sell">Available</th><th rowspan="2">In stock</th>
  <th rowspan="2" title="In shipments created but not picked up yet">In shipments</th><th rowspan="2">On order</th><th rowspan="2" title="Available + On order">Total</th>
  <?php if ($admin): ?><th colspan="<?= count($RST_M) ?>" class="rsh" title="Amazon Restock Inventory: units Amazon recommends to send to each country">Recommended restock</th><th rowspan="2">Value incl. freight</th><?php endif; ?></tr>
<tr><?php if ($admin) foreach ($RST_M as $mn): ?><th class="mk"><?= h($mn) ?></th><?php endforeach; ?></tr>
</thead>
<tbody>
<?php $lastM = null; foreach ($rows as $i => $r): $pid = (int)$r['id']; $m = trim((string)$r['model']);
  if ($m !== $lastM): $lastM = $m; ?><tr class="mdl"><td colspan="<?= $cols ?>"><?= h($m !== '' ? $m : 'Other') ?></td></tr><?php endif;
  $ins = $r['_ins']; $av = $r['_av']; $lf = $r['_lf']; ?>
<tr class="row <?= $r['_cls'] ?>" tabindex="0" aria-expanded="false" data-d="d<?= $i ?>">
  <td><span class="chev">›</span> <?= pname($r) ?><?= $r['active'] ? '' : ' (archived)' ?><?= !empty($r['no_reorder']) ? ' <span class="note">restock off</span>' : '' ?></td>
  <td class="av"<?= $av < 0 ? ' style="color:var(--red)"' : '' ?>><?= num($av) ?></td>
  <td><?= $r['stock'] ? num($r['stock']) : '' ?></td>
  <td><?= $ins ? '<span title="' . h($insh[$pid]['refs']) . '" style="cursor:help;border-bottom:1px dotted currentColor">' . num($ins) . '</span>' : '' ?></td>
  <td><?= $r['on_order'] ? num($r['on_order']) : '' ?></td>
  <td><b><?= ($av + $r['on_order']) ? num($av + $r['on_order']) : '' ?></b></td>
  <?php if ($admin): foreach ($RST_M as $mk => $mn): $q = $rst[$pid][$mk] ?? 0; $rstT[$mk] += $q; ?><td class="rs"><?= $q ? num($q) : '' ?></td><?php endforeach; ?>
  <td><?php if ($r['_v']): ?><b><?= money($lf === null ? $r['_v'] : $r['_vl']) ?></b><?= $lf === null ? '<br><span class="note">no freight yet</span>' : (isset($est[$pid]) ? '<br><span class="note">freight est.</span>' : '') ?><?php endif; ?></td><?php endif; ?>
</tr>
<tr class="det" id="d<?= $i ?>" hidden><td colspan="<?= $cols ?>"><dl>
  <div><dt>Cartons</dt><dd><?= $r['_cart'] === null ? '–' : $cartons($r['_cart']) ?></dd></div>
  <?php if ($admin): ?>
  <div><dt>Unit cost</dt><dd><?= money($r['price']) ?></dd></div>
  <div><dt>Unit cost incl. freight</dt><dd><?= $lf === null ? '—' : money((float)$r['price'] + $lf) . (isset($est[$pid]) ? ' <span class="note">est.</span>' : '') ?></dd></div>
  <div><dt>Value without freight</dt><dd><?= money($r['_v']) ?></dd></div>
  <?php if ((float)$r['on_order_value']): ?><div><dt>Value on order</dt><dd><?= money($r['on_order_value']) ?></dd></div><?php endif; ?>
  <?php endif; ?>
  <?php if ($r['min_stock'] !== null && empty($r['no_reorder'])): ?><div><dt>Minimum</dt><dd><?= num($r['min_stock']) ?></dd></div><?php endif; ?>
</dl></td></tr>
<?php endforeach; ?>
</tbody>
<tfoot><tr><td>Total</td><td><?= num($tav) ?></td><td><?= num($tq) ?></td><td><?= $tin ? num($tin) : '' ?></td><td><?= $to ? num($to) : '' ?></td><td><?= num($tav + $to) ?></td>
<?php if ($admin): foreach ($rstT as $q): ?><td style="text-align:center;color:var(--green);background:var(--rs)"><?= $q ? num($q) : '' ?></td><?php endforeach; ?><td><?= money($tvl) ?></td><?php endif; ?></tr></tfoot>
</table></div>
<?php if (!$rows): ?><p>No products yet. <a href="products.php">Add the first one</a>.</p><?php endif; ?>
<p class="legend">The stripe on the left: <b style="color:var(--red)">red</b> — order now, <b style="color:var(--blue)">blue</b> — low, already on order, <b style="color:var(--green)">green</b> — enough. Click a product for cartons and cost. More in Help.</p>
</div>
<script>
document.querySelectorAll('.sk .row').forEach(function (r) {
  var t = function () { var d = document.getElementById(r.dataset.d); if (!d) return; var o = d.hidden; d.hidden = !o; r.setAttribute('aria-expanded', o); };
  r.addEventListener('click', function (e) { if (e.target.closest('a')) return; t(); });
  r.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); t(); } });
});
</script>
<?php page_end();
