/**
 * Helpers for pointer-based drag-and-drop in Blazor (WebView2).
 *
 * When pointerdown fires on an element, the browser gives it implicit
 * pointer capture, which prevents pointerenter/pointerleave from firing
 * on sibling elements. Releasing the capture restores normal behaviour.
 */
window.cfxDrag = {
    _ghost: null,
    _offsetX: 0,
    _offsetY: 0,
    _pointerY: 0,
    _scrollContainer: null,
    _scrollFrame: null,
    _onMove: null,
    _onUp: null,

    releaseCapture: (element, pointerId) => {
        try { element.releasePointerCapture(pointerId); } catch { }
    },

    applyGrabCursors: (container) => {
        if (!container) return;
        const handles = container.querySelectorAll('.drag-handle');
        handles.forEach(h => {
            h.style.cursor = 'pointer';
            h.querySelectorAll('*').forEach(c => c.style.cursor = 'pointer');
        });
    },

    /**
     * Creates a semi-transparent clone of the dragged row and follows the
     * pointer until endDrag is called.
     * @param {Element} handleEl  The .drag-handle element that was pressed.
     * @param {Element} scrollContainer The scrollable container that should auto-scroll.
     * @param {number}  clientX         PointerEvent.clientX at press time.
     * @param {number}  clientY         PointerEvent.clientY at press time.
     */
    startDrag: (handleEl, scrollContainer, clientX, clientY) => {
        const self = window.cfxDrag;
        self.endDrag(); // clean up any stale ghost

        const row = handleEl.closest('.soundfont-item');
        if (!row) return;

        const rect = row.getBoundingClientRect();

        // Clone the row – keep original classes so content layout is preserved
        const ghost = row.cloneNode(true);
        ghost.classList.add('cfx-drag-ghost');
        // Apply positioning inline so it overrides any class-based styles
        ghost.style.position = 'fixed';
        ghost.style.zIndex = '10000';
        ghost.style.pointerEvents = 'none';
        ghost.style.opacity = '0.7';
        ghost.style.width = rect.width + 'px';
        ghost.style.left = rect.left + 'px';
        ghost.style.top = rect.top + 'px';
        ghost.style.border = '1px solid var(--mud-palette-primary)';
        ghost.style.borderRadius = '4px';
        ghost.style.boxShadow = '0 8px 24px rgba(0,0,0,0.35)';
        ghost.style.background = 'var(--mud-palette-surface)';
        ghost.style.transition = 'none';
        document.body.appendChild(ghost);

        self._ghost = ghost;
        self._offsetX = clientX - rect.left;
        self._offsetY = clientY - rect.top;
        self._pointerY = clientY;
        self._scrollContainer = scrollContainer;

        const autoScroll = () => {
            if (!self._ghost || !self._scrollContainer) {
                self._scrollFrame = null;
                return;
            }

            const containerRect = self._scrollContainer.getBoundingClientRect();
            const threshold = Math.min(72, containerRect.height / 3);
            let delta = 0;

            if (self._pointerY < containerRect.top + threshold) {
                const intensity = Math.min(1, (containerRect.top + threshold - self._pointerY) / threshold);
                delta = -Math.max(4, Math.round(intensity * 20));
            } else if (self._pointerY > containerRect.bottom - threshold) {
                const intensity = Math.min(1, (self._pointerY - (containerRect.bottom - threshold)) / threshold);
                delta = Math.max(4, Math.round(intensity * 20));
            }

            if (delta !== 0) {
                self._scrollContainer.scrollTop += delta;
            }

            self._scrollFrame = window.requestAnimationFrame(autoScroll);
        };

        // Pointer-move handler (runs at full frame-rate via JS, not Blazor)
        self._onMove = (e) => {
            if (!self._ghost) return;
            self._pointerY = e.clientY;
            self._ghost.style.left = (e.clientX - self._offsetX) + 'px';
            self._ghost.style.top = (e.clientY - self._offsetY) + 'px';
        };

        // Safety-net pointer-up in case Blazor's handler doesn't fire
        self._onUp = () => self.endDrag();

        document.addEventListener('pointermove', self._onMove);
        document.addEventListener('pointerup', self._onUp);
        self._scrollFrame = window.requestAnimationFrame(autoScroll);
    },

    /** Removes the drag ghost and cleans up listeners. */
    endDrag: () => {
        const self = window.cfxDrag;
        if (self._ghost) {
            self._ghost.remove();
            self._ghost = null;
        }
        if (self._onMove) {
            document.removeEventListener('pointermove', self._onMove);
            self._onMove = null;
        }
        if (self._onUp) {
            document.removeEventListener('pointerup', self._onUp);
            self._onUp = null;
        }
        if (self._scrollFrame) {
            window.cancelAnimationFrame(self._scrollFrame);
            self._scrollFrame = null;
        }
        self._scrollContainer = null;
        self._pointerY = 0;
    }
};

