/**
 * Click-and-drag support for `.gallery-slider__viewport` (see
 * templates/components/_gallery-slider.html.twig / assets/styles/components/_gallery-slider.scss).
 *
 * The viewport is a plain `overflow-x: auto` element, so touch/trackpad swiping already
 * works natively with zero JS - this module only adds the desktop-mouse equivalent (press
 * and drag, like a finger swipe) since a hidden scrollbar otherwise leaves mouse-only users
 * with no way to move it. Pointer Events, same approach as
 * assets/components/before-after-slider.ts, scoped to `pointerType === 'mouse'` so it never
 * fights the browser's native touch/pen scrolling.
 */

export function computeDragScrollLeft(startScrollLeft: number, startX: number, currentX: number): number {
    return startScrollLeft - (currentX - startX);
}

class DragScrollSlider {
    private viewport: HTMLElement;
    private isDragging = false;
    private startX = 0;
    private startScrollLeft = 0;

    constructor(viewport: HTMLElement) {
        this.viewport = viewport;
        this.bindPointerEvents();
    }

    private bindPointerEvents(): void {
        this.viewport.addEventListener('pointerdown', (event: PointerEvent) => {
            if (event.pointerType !== 'mouse') {
                return;
            }

            event.preventDefault();
            this.isDragging = true;
            this.startX = event.clientX;
            this.startScrollLeft = this.viewport.scrollLeft;
            this.viewport.setPointerCapture(event.pointerId);
            this.viewport.classList.add('is-dragging');

            const onMove = (moveEvent: PointerEvent): void => {
                if (!this.isDragging) {
                    return;
                }

                this.viewport.scrollLeft = computeDragScrollLeft(this.startScrollLeft, this.startX, moveEvent.clientX);
            };

            const onUp = (upEvent: PointerEvent): void => {
                this.isDragging = false;
                this.viewport.releasePointerCapture(upEvent.pointerId);
                this.viewport.classList.remove('is-dragging');
                this.viewport.removeEventListener('pointermove', onMove);
                this.viewport.removeEventListener('pointerup', onUp);
                this.viewport.removeEventListener('pointercancel', onUp);
            };

            this.viewport.addEventListener('pointermove', onMove);
            this.viewport.addEventListener('pointerup', onUp);
            this.viewport.addEventListener('pointercancel', onUp);
        });

        // Prevent the browser's native "ghost image" drag (would otherwise fire instead of
        // our pointer drag when the mouse press starts on top of an <img>).
        this.viewport.addEventListener('dragstart', event => event.preventDefault());
    }
}

/**
 * Mounts one `DragScrollSlider` per `[data-drag-scroll="true"]` found under `root`
 * (defaults to `document`).
 */
export function initGallerySliders(root: ParentNode = document): void {
    root.querySelectorAll<HTMLElement>('[data-drag-scroll="true"]').forEach(viewport => {
        new DragScrollSlider(viewport);
    });
}
