import { noop } from "../../core/function/noop.js";
import Vector2 from "../../core/geom/Vector2.js";
import { PointerDevice } from "../input/devices/PointerDevice.js";

/**
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export class DraggableAspect {
    /**
     *
     * @param {EventTarget} el
     * @param {function} [dragStart=noop]
     * @param {(position:Vector2,origin:Vector2)=>*} [drag=noop]
     * @param {function} [dragEnd=noop]
     * @param {boolean} [stopPropagation=true] prevent propagation of pointer events up the DOM tree
     */
    constructor({ el, dragStart = noop, drag = noop, dragEnd = noop, stopPropagation = true }) {
        /**
         *
         * @type {PointerDevice}
         * @readonly
         * @private
         */
        this.pointerLocal = new PointerDevice(el);

        /**
         *
         * @type {PointerDevice}
         * @readonly
         * @private
         */
        const pointerGlobal = this.pointerGlobal = new PointerDevice(window);

        const dragOriginalPosition = new Vector2();
        const pointer_position_last = new Vector2();

        if (stopPropagation) {
            this.pointerLocal.on.down.add((p, e) => {
                e.stopPropagation();
            });
        }

        this.pointerLocal.on.dragStart.add((position) => {
            dragOriginalPosition.copy(position);
            pointer_position_last.copy(position);
            pointerGlobal.start();

            dragStart(position);

            function stopDrag(position) {
                pointerGlobal.on.up.remove(stopDrag);
                pointerGlobal.stop();

                dragEnd(position, dragOriginalPosition);
            }

            pointerGlobal.on.up.add(stopDrag);
        });

        this.pointerGlobal.on.move.add((position, event, delta) => {
            drag(position, dragOriginalPosition, delta);
        });
    }

    /**
     *
     * @returns {PointerDevice}
     */
    getPointer() {
        return this.pointerLocal;
    }

    start() {
        this.pointerLocal.start();
    }

    stop() {
        this.pointerLocal.stop();
        this.pointerGlobal.stop();
    }
}
