// shared/elevation.js — admin elevation toggle.
//
// Sudo-style model: admins behave as normal users by default; clicking
// the header toggle elevates the session so admin escape hatches (WORM
// bypass, .zddc edit authority, profile admin scaffolds) start firing.
// State is carried in a `zddc-elevate=1` cookie that the server reads
// via handler.ACLMiddleware → zddc.Principal{Elevated}.
//
// Only renders the toggle when /.profile/access reports the caller has
// some admin scope — a non-admin sees nothing, which keeps the chrome
// quiet for the common case. The toggle fades in once access loads so
// non-admins never even see the affordance flash.
//
// Click flow: set/clear the cookie, then reload the page so the server
// sees the new state on the next render. The reload is intentional —
// admin scaffolds in tool HTML are server-rendered for some tools, so
// a soft state flip on the client alone wouldn't reach those.
(function () {
    'use strict';

    if (!window.zddc) window.zddc = {};
    if (window.zddc.elevation) return;

    var COOKIE_NAME = 'zddc-elevate';

    function isElevated() {
        var parts = document.cookie.split(';');
        for (var i = 0; i < parts.length; i++) {
            var kv = parts[i].trim().split('=');
            if (kv[0] === COOKIE_NAME && kv[1] === '1') return true;
        }
        return false;
    }

    function setElevated(on) {
        if (on) {
            // SameSite=Lax blocks cross-site form-post / image-tag CSRF
            // shapes. Max-Age caps the elevation window so a forgotten
            // tab doesn't leave admin powers active indefinitely (sudo's
            // 5-minute precedent informs the number — 30 minutes is a
            // reasonable trade between annoyance and exposure).
            document.cookie = COOKIE_NAME + '=1; Path=/; SameSite=Lax; Max-Age=1800';
        } else {
            document.cookie = COOKIE_NAME + '=; Path=/; SameSite=Lax; Max-Age=0';
        }
    }

    async function fetchAccess() {
        try {
            var resp = await fetch('/.profile/access', {
                headers: { 'Accept': 'application/json' },
                credentials: 'same-origin',
                cache: 'no-cache'
            });
            if (!resp.ok) return null;
            return await resp.json();
        } catch (_e) {
            return null;
        }
    }

    function render(host, elevated) {
        host.classList.remove('hidden');
        host.innerHTML =
            '<input type="checkbox" id="elevation-checkbox"'
            + (elevated ? ' checked' : '') + '>'
            + '<label for="elevation-checkbox" class="elevation-toggle__label">'
            + 'Admin</label>';
        var cb = host.querySelector('#elevation-checkbox');
        cb.addEventListener('change', function () {
            setElevated(cb.checked);
            // Hard reload so server-rendered admin surfaces (profile
            // page scaffolds, hidden-entry listings) catch up. URL
            // and scroll state are preserved by the browser's normal
            // back-forward cache rules.
            window.location.reload();
        });
    }

    // Page-wide affordances when elevation is active. The toggle alone
    // is easy to miss — admin mode silently bypasses WORM and ACL
    // restrictions, which produces surprising "I shouldn't have been
    // able to do that" moments. A body class + a sticky banner with a
    // one-click disable make the armed state unmistakable.
    function applyArmedChrome(elevated) {
        var b = document.body;
        if (!b) return;
        if (elevated) b.classList.add('is-elevated');
        else b.classList.remove('is-elevated');

        var banner = document.getElementById('elevation-banner');
        if (elevated) {
            if (!banner) {
                banner = document.createElement('div');
                banner.id = 'elevation-banner';
                banner.className = 'elevation-banner';
                banner.setAttribute('role', 'alert');
                banner.innerHTML =
                    '<span class="elevation-banner__dot" aria-hidden="true"></span>'
                    + '<span class="elevation-banner__msg">'
                    +   'Admin mode is on — write access bypasses WORM and ACL safeguards.'
                    + '</span>'
                    + '<button type="button" class="elevation-banner__off" id="elevation-banner-off">'
                    +   'Drop admin'
                    + '</button>';
                document.body.insertBefore(banner, document.body.firstChild);
                var off = banner.querySelector('#elevation-banner-off');
                if (off) off.addEventListener('click', function () {
                    setElevated(false);
                    window.location.reload();
                });
            }
        } else if (banner) {
            banner.parentNode.removeChild(banner);
        }
    }

    async function init() {
        // Body chrome applies on every page load whether or not the
        // header has a toggle slot — the banner needs to surface in
        // tools / pages that don't host the toggle (e.g. iframed
        // classifier inside browse's grid mode), so the user can't
        // accidentally write through an elevated context elsewhere.
        applyArmedChrome(isElevated());

        var host = document.getElementById('elevation-toggle');
        if (!host) return; // tool doesn't include the slot yet — no-op
        var access = await fetchAccess();
        if (!access) return; // anonymous / endpoint missing — no-op
        // Surface ONLY for users who have admin authority somewhere.
        // /.profile/access ships `can_elevate` as an elevation-
        // INDEPENDENT signal — true for any user named in any admin
        // list, regardless of current cookie state. The other flags
        // (is_super_admin, has_any_admin_scope) reflect EFFECTIVE
        // authority and would be false for an un-elevated admin
        // who hasn't toggled yet — so we can't gate on those.
        if (!access.can_elevate) return;
        render(host, isElevated());
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    window.zddc.elevation = { isElevated: isElevated, setElevated: setElevated };
})();
