/**
 * AppShell — Layer 1 layout scaffold
 *
 * ┌─────────────────────────────────┐  ← fixed banner (top, optional)
 * ├─────────────────────────────────┤
 * │  message (optional, dismissible)│
 * ├─────────────────────────────────┤
 * │                                 │
 * │   surface (fills remaining)     │
 * │                                 │
 * ├─────────────────────────────────┤
 * │  footer (optional)              │
 * ├─────────────────────────────────┤
 * └─────────────────────────────────┘  ← fixed banner (bottom, same as top)
 *
 * Props:
 *   banner    — { text, variant } or null  (one config → top AND bottom)
 *   message   — { text, variant } or null  (dismissible)
 *   footer    — VNode children or null
 *   children  — Surface content
 */
const { html } = window;
const { useState, useEffect, useRef, useReducer } = hooks;

function ShellBanner({ position, text, variant = 'info' }) {
    const ref = useRef(null);
    const prop = position === 'top' ? '--banner-top-height' : '--banner-bottom-height';

    useEffect(() => {
        if (ref.current) {
            const h = ref.current.offsetHeight + 'px';
            document.documentElement.style.setProperty(prop, h);
        }
        return () => document.documentElement.style.setProperty(prop, '0px');
    }, [text, prop]);

    return html`
        <div class="sw-shell__banner sw-shell__banner--${position} sw-shell__banner--${variant}" ref=${ref}>
            <span class="sw-shell__banner-text">${text}</span>
        </div>
    `;
}

/**
 * Renders all components registered in a named slot.
 * Re-renders when sw.slots changes (via 'slots.changed' event).
 */
function SlotRenderer({ name }) {
    const [, tick] = useReducer(n => n + 1, 0);

    useEffect(() => {
        if (!window.sw) return;
        const off = window.sw.on('slots.changed', (e) => {
            if (e.slot === name) tick();
        });
        return () => { if (typeof off === 'function') off(); else window.sw.off('slots.changed', tick); };
    }, [name]);

    const items = window.sw?.slots?.get(name) || [];
    if (!items.length) return null;
    return html`<div class="sw-slot sw-slot--${name}">
        ${items.map(i => html`<${i.component} key=${i.id} />`)}
    </div>`;
}

export function AppShell({ banner, message, footer, children }) {
    const [msgDismissed, setMsgDismissed] = useState(false);

    const showMsg = message && !msgDismissed;

    return html`
        <div class="sw-shell">
            ${banner && html`
                <${ShellBanner} position="top" text=${banner.text} variant=${banner.variant} />
            `}

            <div class="sw-shell__body">
                ${showMsg && html`
                    <div class="sw-shell__announcement">
                        <div class="sw-shell__announcement-inner sw-shell__announcement--${message.variant || 'info'}">
                            <span class="sw-shell__announcement-text">${message.text}</span>
                            <button class="sw-shell__banner-close" onClick=${() => setMsgDismissed(true)} aria-label="Dismiss">×</button>
                        </div>
                    </div>
                `}

                <${SlotRenderer} name="toolbar" />
                <${SlotRenderer} name="surface.header" />

                <main class="sw-shell__surface">
                    ${children}
                </main>

                ${footer && html`
                    <footer class="sw-shell__footer">
                        ${footer}
                    </footer>
                `}

                <${SlotRenderer} name="statusbar" />
            </div>

            ${banner && html`
                <${ShellBanner} position="bottom" text=${banner.text} variant=${banner.variant} />
            `}
        </div>
    `;
}
