/**
 * ScopeScaleWrapper
 *
 * Wraps a scope's items/header block so that on narrow screens the
 * whole thing scales down as a unit rather than overflowing.
 *
 * Critical CSS behaviour used here:
 *
 *   overflow: clip
 *     Clips the inner element at the outer's edges — identical to
 *     `overflow: hidden` visually, BUT does NOT create a scroll
 *     container. This matters because `position: sticky` elements
 *     inside reference the nearest scroll container ancestor. With
 *     `overflow: hidden` that would be this element (which doesn't
 *     scroll → sticky breaks). With `overflow: clip` there is no
 *     new scroll container → sticky still references the page.
 *
 *   transform: scale() + transform-origin: top left
 *     Visually shrinks the inner block. Layout size is unaffected
 *     (transform never changes layout). We compensate by setting
 *     the outer div's explicit height = naturalHeight × scale, and
 *     clipping with overflow: clip.
 */

import type { Component, JSX } from 'solid-js';
import { onMount, onCleanup } from 'solid-js';

interface ScopeScaleWrapperProps {
    children: JSX.Element;
    class?: string;
    /** Minimum scale factor — won't zoom below this. Default: 0.65 */
    minScale?: number;
}

const ScopeScaleWrapper: Component<ScopeScaleWrapperProps> = (props) => {
    let outerEl: HTMLDivElement | undefined;
    let innerEl: HTMLDivElement | undefined;

    const recalculate = () => {
        if (!outerEl || !innerEl) return;
        const minScale = props.minScale ?? 0.65;

        // ── Step 1: measure the inner's TRUE natural width ───────────────
        // Must set max-content BEFORE measuring — if width is unset the
        // element stretches to fill the parent, making scrollWidth == outerWidth
        // and we'd never think scaling is needed.
        innerEl.style.width = 'max-content';
        innerEl.style.transform = 'none';
        outerEl.style.height = '';
        outerEl.style.overflow = '';
        void outerEl.offsetWidth; // force reflow

        const naturalWidth = innerEl.scrollWidth;
        const naturalHeight = innerEl.scrollHeight;
        const outerWidth = outerEl.clientWidth;

        if (naturalWidth <= outerWidth) {
            // ── Fits naturally — fill available width, no clip/scale ──────
            innerEl.style.width = '100%';
            innerEl.style.transform = '';
            outerEl.style.height = '';
            outerEl.style.overflow = '';
        } else {
            // ── Too wide — scale down ─────────────────────────────────────
            const rawScale = outerWidth / naturalWidth;
            const newScale = Math.max(minScale, rawScale);

            // Fix inner to its natural pixel width so transform-origin math
            // is reliable, then scale from the top-left corner
            innerEl.style.width = `${naturalWidth}px`;
            innerEl.style.transformOrigin = 'top left';
            innerEl.style.transform = `scale(${newScale})`;

            // Set outer height to visual (post-scale) height so no dead space
            // appears below the scaled block
            outerEl.style.height = `${naturalHeight * newScale}px`;

            // overflow: clip — clips layout overflow WITHOUT creating a scroll
            // container, so position:sticky inside still works against the page
            outerEl.style.overflow = 'clip';
        }
    };

    let ro: ResizeObserver;

    onMount(() => {
        ro = new ResizeObserver(recalculate);
        if (outerEl) ro.observe(outerEl);
        if (innerEl) ro.observe(innerEl);
        recalculate();
    });

    onCleanup(() => ro?.disconnect());

    return (
        <div ref={outerEl} class={`relative ${props.class ?? ''}`}>
            <div ref={innerEl}>
                {props.children}
            </div>
        </div>
    );
};

export default ScopeScaleWrapper;
