<?php
/**
 * Native mobile navigation for the console SPA shell (phones only).
 *
 * Rendered at BODY level (included after </nav> in project-navbar.php) so it is
 * NOT trapped inside the fixed navbar's stacking context — the reason the old
 * bottom-sheet dropdown was un-tappable (its backdrop painted over it). Everything
 * here is a real <a> link + a self-owned scrim + vanilla JS, so it is reliable.
 *
 * Two surfaces, both hidden on desktop by CSS (.ppm-* rules live in
 * project-shell-mobile.css, all inside @media max-width):
 *   • a bottom TAB BAR   — 4 most-used screens + a Menu button (thumb reach)
 *   • a left DRAWER      — every screen, grouped & foldable, + Save/Build/History/Close
 *
 * Expects $baseUrl and $project in scope (both always set by project-navbar.php).
 */
$__slug        = (string) ($project['slug'] ?? '');
$__standalone  = \PpPhp\Core\ProjectDatabaseProfile::isStandaloneSlug($__slug);
$__pages       = \PpPhp\Core\ProjectNav::spaPages($__standalone);
$__projBase    = rtrim((string) $baseUrl, '/') . '/project/' . rawurlencode($__slug);
$__h           = static fn ($s) => htmlspecialchars((string) $s, ENT_QUOTES);

// Current screen (e.g. "/tables") for active highlighting.
$__path = (string) parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
$__cur  = '';
if (preg_match('#/project/[^/]+(/[a-z0-9-]+)#i', $__path, $__m)) { $__cur = strtolower($__m[1]); }
if ($__cur === '' ) { $__cur = '/workspace'; }

// Bottom-bar quick screens (uri => icon). Kept to four so targets stay wide.
$__quick = [
    ['uri' => '/workspace', 'icon' => 'grid-1x2',    'label' => 'Home'],
    ['uri' => '/tables',    'icon' => 'table',        'label' => 'Tables'],
    ['uri' => '/designer',  'icon' => 'palette',      'label' => 'Design'],
    ['uri' => '/output',    'icon' => 'box-arrow-right', 'label' => 'Ship'],
];
?>
<!-- ══ Bottom tab bar (phone) ══ -->
<nav class="ppm-tabbar" aria-label="Quick navigation">
    <?php foreach ($__quick as $q):
        $active = $__cur === $q['uri'];
        $locked = $__standalone && in_array($q['uri'], \PpPhp\Core\ProjectNav::DB_ONLY, true);
    ?>
        <a class="ppm-tab<?= $active ? ' is-active' : '' ?><?= $locked ? ' is-locked' : '' ?>"
           href="<?= $locked ? '#' : $__projBase . $__h($q['uri']) ?>"
           <?= $locked ? 'aria-disabled="true"' : '' ?>>
            <i class="bi bi-<?= $__h($q['icon']) ?>"></i>
            <span><?= $__h($q['label']) ?></span>
        </a>
    <?php endforeach; ?>
    <button type="button" class="ppm-tab ppm-tab-menu" data-ppm-open aria-controls="ppmDrawer" aria-label="Open menu">
        <i class="bi bi-grid-3x3-gap-fill"></i><span>Menu</span>
    </button>
</nav>

<!-- ══ Left drawer (phone) ══ -->
<div class="ppm-drawer" id="ppmDrawer" aria-hidden="true">
    <div class="ppm-scrim" data-ppm-close></div>
    <aside class="ppm-panel" role="dialog" aria-modal="true" aria-label="All screens">
        <header class="ppm-head">
            <span class="ppm-brand"><?= \PpPhp\Core\Brand::mark(26) ?><span class="ppm-brand-t"><?= $__h($project['name'] ?? 'Project') ?></span></span>
            <button type="button" class="ppm-x" data-ppm-close aria-label="Close menu"><i class="bi bi-x-lg"></i></button>
        </header>

        <div class="ppm-scroll">
            <?php
            $__grp = null;
            foreach ($__pages as $p):
                $g = (string) ($p['group'] ?? '');
                if ($g !== $__grp):
                    if ($__grp !== null) { echo "</div></details>"; }
                    $__grp = $g;
                    echo '<details class="ppm-group" open><summary class="ppm-group-h">' . $__h($g) . '<i class="bi bi-chevron-down"></i></summary><div class="ppm-group-body">';
                endif;
                $active = $__cur === ($p['uri'] ?? '');
                if (!empty($p['locked'])): ?>
                    <span class="ppm-item is-locked" aria-disabled="true" title="Needs a database — this is a standalone app">
                        <span class="ppm-ico"><i class="bi bi-<?= $__h($p['icon']) ?>"></i></span>
                        <span class="ppm-lbl"><?= $__h($p['label']) ?></span>
                        <i class="bi bi-lock-fill ppm-lock"></i>
                    </span>
                <?php else: ?>
                    <a class="ppm-item<?= $active ? ' is-active' : '' ?>" href="<?= $__projBase . $__h($p['uri']) ?>" data-ppm-nav>
                        <span class="ppm-ico"><i class="bi bi-<?= $__h($p['icon']) ?>"></i></span>
                        <span class="ppm-lbl"><?= $__h($p['label']) ?></span>
                        <?php if ($active): ?><i class="bi bi-check2 ppm-check"></i><?php endif; ?>
                    </a>
                <?php endif;
            endforeach;
            if ($__grp !== null) { echo "</div></details>"; }
            ?>
        </div>

        <footer class="ppm-foot">
            <button type="button" class="ppm-act ppm-act-primary" id="ppmSave"><i class="bi bi-save"></i> Save</button>
            <button type="button" class="ppm-act ppm-act-build" id="ppmBuild"><i class="bi bi-hammer"></i> Build</button>
            <button type="button" class="ppm-act" id="ppmVh"><i class="bi bi-clock-history"></i> History</button>
            <a class="ppm-act" href="<?= $__h(rtrim((string) $baseUrl, '/')) ?>/projects"><i class="bi bi-x-circle"></i> Close</a>
        </footer>
    </aside>
</div>

<script>
(function () {
    var drawer = document.getElementById('ppmDrawer');
    if (!drawer || drawer.dataset.ppmReady) return;
    drawer.dataset.ppmReady = '1';
    var root = document.documentElement;
    function open()  { drawer.classList.add('is-open');  drawer.setAttribute('aria-hidden', 'false'); root.classList.add('ppm-lock'); }
    function close() { drawer.classList.remove('is-open'); drawer.setAttribute('aria-hidden', 'true');  root.classList.remove('ppm-lock'); }
    window.ppmOpenDrawer = open; window.ppmCloseDrawer = close;

    document.querySelectorAll('[data-ppm-open]').forEach(function (b) {
        b.addEventListener('click', function (e) { e.preventDefault(); open(); });
    });
    drawer.querySelectorAll('[data-ppm-close]').forEach(function (b) {
        b.addEventListener('click', close);
    });
    document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && drawer.classList.contains('is-open')) close(); });
    // Navigating (real link) — let it proceed, just close for the brief moment.
    drawer.querySelectorAll('[data-ppm-nav]').forEach(function (a) {
        a.addEventListener('click', function () { setTimeout(close, 30); });
    });
    // Drawer actions proxy the always-present desktop toolbar buttons (they exist
    // in the DOM even while hidden; .click() still fires their handlers).
    function proxy(fromId, toSelector) {
        var from = document.getElementById(fromId); if (!from) return;
        from.addEventListener('click', function (e) {
            e.preventDefault();
            var t = document.querySelector(toSelector);
            if (t) t.click();
            close();
        });
    }
    proxy('ppmSave', '#btnSaveProject');
    proxy('ppmBuild', '#btnBuildProject');
    proxy('ppmVh', '[data-vh-open]');
})();

/* ── Edge drawers: turn each SPA page's LIST panel (left) and PROPERTIES /
   INSPECTOR panel (right) into slide-in drawers, freeing the canvas to full
   width. Config-driven so it's dynamic per page; the panels keep their own DOM
   + module JS (we only reposition them).

   Robustness (learned from live testing):
   • Many modules render their panels via AJAX AFTER DOMContentLoaded, and some
     RE-render (replace) them later. A MutationObserver + short poll (re)attaches
     drawers whenever a configured panel appears or is swapped — so Security /
     Events / Custom Files stop "not opening".
   • Selecting an item in a LEFT list-drawer auto-closes it (and, where a page
     has a paired RIGHT panel, opens that next — e.g. Events: pick table → pick
     event) so the canvas result is actually revealed. `closeOn` names the
     selection leaves; toggles / search / row switches are ignored. ── */
(function () {
    var MQ = '(max-width: 991.98px)';

    // Convention: LEFT = lists / navigation, RIGHT = properties / inspector.
    // Default left selector is the shared '.left-panel'; custom modules name theirs.
    // `closeOn`  → CSS selector for the "selection leaf" that should collapse the
    //              drawer after tapping (absent = drawer only closes via scrim/handle,
    //              e.g. the Designer palette & properties you keep working in).
    // `advance`  → after a selection, open this side's drawer instead of closing.
    var CFG = {
        '/tables':   { left: { label: 'Tables',   icon: 'table',       closeOn: 'li, a[href], [data-table]' } },
        '/query':    { left: { label: 'Tables',   icon: 'table',       closeOn: 'li, a[href], [data-table]' } },
        '/pages':    { left: { label: 'Tables',   icon: 'table',       closeOn: 'li, a[href], [data-table]' } },
        '/fields':   { left: { label: 'Tables',   icon: 'table',       closeOn: 'li, a[href], [data-table]' } },
        '/security': { left: { label: 'Sections', icon: 'shield-lock', closeOn: 'li, a[href], [data-table], [data-section]' } },
        '/misc':     { left: { label: 'Sections', icon: 'list-ul',     closeOn: 'a[href], .list-group-item, [data-tab]' } },
        '/designer': { left:  { sel: '#ppdLeftPanel',  label: 'Add',        icon: 'plus-square' },
                       right: { sel: '#ppdRightPanel', label: 'Properties', icon: 'sliders2' } },
        '/style':    { left:  { sel: '.sp-list', label: 'Themes', icon: 'palette', closeOn: '.sp-item, li, a[href], [data-theme]' },
                       right: { sel: '.sp-preview-wrap', label: 'Preview', icon: 'eye' }, hide: ['.sp-resizer'] },
        // Events tree is table → section → events. A table `.ev-node` only EXPANDS
        // (it's a toggle, ignored); the panel is loaded by a global category
        // (.ev-node[data-scope=global]) or a table SECTION (.ev-tbl-child) — those
        // close the tree and advance to the Events panel.
        '/events':   { left:  { sel: '#evTree',  label: 'Tables', icon: 'diagram-3', closeOn: '.ev-node[data-scope="global"], .ev-tbl-child', advance: 'right' },
                       right: { sel: '#evPanel', label: 'Events', icon: 'lightning-charge', closeOn: '.ev-row-info, .ev-row-label' }, hide: ['.ev-resizer'] },
        '/custom-files': { left: { sel: '.cf-tree', label: 'Files', icon: 'folder2-open', closeOn: '.cf-node[data-type="file"]' } },
        '/notifications': { left: { sel: '.nr-side', label: 'Filters', icon: 'funnel', closeOn: '.nr-item, a[href], [data-filter]' } }
    };
    var m = (location.pathname || '').match(/\/project\/[^/]+(\/[a-z0-9-]+)/i);
    var uri = m ? m[1].toLowerCase() : '/workspace';
    var cfg = CFG[uri];
    if (!cfg) return;

    // Never auto-close from a search box, a group/table expand toggle, a row on/off
    // switch, etc. ([data-act^=toggle] = Events tree expanders.)
    var IGNORE = 'input, textarea, select, label, summary, [aria-expanded], [contenteditable], .ppm-handle, .ev-row-tog, [data-act^="toggle"], [data-ppm-noclose]';

    var drawers = {};   // side -> { el, handle }
    var scrim = null;

    function mq() { return window.matchMedia(MQ).matches; }

    function ensureScrim() {
        if (scrim && document.body.contains(scrim)) return;
        scrim = document.createElement('div');
        scrim.className = 'ppm-edge-scrim'; scrim.id = 'ppmEdgeScrim';
        scrim.addEventListener('click', closeAll);
        document.body.appendChild(scrim);
    }
    function closeAll() {
        Object.keys(drawers).forEach(function (k) {
            drawers[k].el.classList.remove('is-open');
            drawers[k].handle.hidden = false;
        });
        if (scrim) scrim.classList.remove('is-open');
        document.documentElement.classList.remove('ppm-lock');
    }
    function openDrawer(side) {
        var rec = drawers[side]; if (!rec) return;
        ensureScrim();
        Object.keys(drawers).forEach(function (k) {
            var on = k === side;
            drawers[k].el.classList.toggle('is-open', on);
            drawers[k].handle.hidden = on;
        });
        scrim.classList.add('is-open');
        document.documentElement.classList.add('ppm-lock');
    }

    // (Re)attach one side. Safe to call repeatedly: no-ops if already bound to the
    // same node; rebinds cleanly if the module replaced the panel element.
    function attach(side, c) {
        var el = document.querySelector(c.sel || '.left-panel');
        if (!el) return;
        var rec = drawers[side];
        if (rec && rec.el === el) return;                 // already bound to this node
        // The module REPLACED its panel node (Security/Events re-render). Preserve the
        // open state onto the new node — otherwise the drawer silently snaps shut while
        // its handle stays hidden = "frozen / not showing".
        var wasOpen = false;
        if (rec) { wasOpen = rec.el.classList.contains('is-open'); rec.el.classList.remove('ppm-edge', 'ppm-edge-' + side, 'is-open'); }

        var ma = el.closest('.main-area'); if (ma) ma.classList.add('ppm-drawerized');
        el.classList.add('ppm-edge', 'ppm-edge-' + side);
        if (wasOpen) el.classList.add('is-open');

        var h = (rec && rec.handle) || document.createElement('button');
        if (!rec) {
            h.type = 'button';
            h.className = 'ppm-handle ppm-handle-' + side;
            h.setAttribute('aria-label', 'Open ' + (c.label || side));
            h.innerHTML = '<i class="bi bi-' + (c.icon || 'list') + '"></i><span class="ppm-handle-t">' + (c.label || '') + '</span>';
            document.body.appendChild(h);
            h.addEventListener('click', function () {
                if ((drawers[side] && drawers[side].el.classList.contains('is-open'))) closeAll();
                else openDrawer(side);
            });
        }

        // Auto-close (or advance) once the user picks something from the list.
        if (c.closeOn) {
            el.addEventListener('click', function (ev) {
                if (ev.target.closest(IGNORE)) return;
                if (!ev.target.closest(c.closeOn)) return;
                setTimeout(function () {
                    if (c.advance && drawers[c.advance]) openDrawer(c.advance);
                    else closeAll();
                }, 200);
            });
        }
        drawers[side] = { el: el, handle: h };
        h.hidden = el.classList.contains('is-open');   // reconcile after (re)bind
    }

    function applyHide() {
        (cfg.hide || []).forEach(function (s) {
            document.querySelectorAll(s).forEach(function (e) { e.classList.add('ppm-hide'); });
        });
    }

    function sync() {
        if (!mq()) { closeAll(); return; }
        if (cfg.left)  attach('left',  cfg.left);
        if (cfg.right) attach('right', cfg.right);
        applyHide();
    }

    // Designer: selecting a component on the canvas should slide the Properties
    // drawer open (otherwise the inspector "opens" off-screen and feels frozen).
    // Hook the designer store's 'ui' event once it exists.
    function wireDesigner() {
        if (uri !== '/designer') return;
        var wired = false;
        function tryWire() {
            if (wired || !(window.PPD && PPD.store && typeof PPD.store.on === 'function')) return;
            wired = true;
            PPD.store.on('ui', function (changed) {
                if (!mq() || !changed || !('selectedId' in changed)) return;
                if (changed.selectedId) openDrawer('right');   // component picked → show its props
            });
        }
        tryWire();
        document.addEventListener('ppphp:designer:ready', tryWire);
        var n = 0, iv = setInterval(function () { tryWire(); if (wired || ++n >= 20) clearInterval(iv); }, 300);
    }

    function boot() {
        sync();
        wireDesigner();
        // Late / re-rendered panels: observe the DOM and re-sync (debounced).
        var t = null;
        var obs = new MutationObserver(function () {
            if (t) return;
            t = setTimeout(function () { t = null; sync(); }, 150);
        });
        obs.observe(document.body, { childList: true, subtree: true });
        // Belt-and-suspenders early polls for slow first paints.
        var n = 0, iv = setInterval(function () { sync(); if (++n >= 12) clearInterval(iv); }, 350);

        document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeAll(); });
        window.addEventListener('resize', function () { if (!mq()) closeAll(); else sync(); });
    }

    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
    else boot();
})();
</script>
