import { setElementProperties } from "./columns";
const LIMEL_DRAG_HANDLE = 'limel-drag-handle';
/**
 * Provides row drag-and-drop reordering configuration for Tabulator
 * using native movableRows with a custom drag handle
 */
export class RowDragManager {
    constructor(pool, reorderEvent, getLanguage) {
        this.pool = pool;
        this.reorderEvent = reorderEvent;
        this.getLanguage = getLanguage;
        this.mutationObserver = null;
        /**
         * Tabulator fires `rowMoved` / `rowMoveCancelled` from its `mouseup`
         * handler. The browser may then dispatch a synthetic `click` on the drop
         * target which would bubble to Tabulator's row-click handling and trigger
         * a spurious row activation. Call this from both events: it installs a
         * one-shot capture-phase click listener that swallows that single click
         * before Tabulator can see it. If no click arrives (rare, but possible),
         * the listener is removed on the next macrotask so it can never swallow a
         * later, intentional click.
         *
         * @param target - Element that should swallow the post-drop click
         * (typically the table host).
         */
        this.armPostDropClickGuard = (target) => {
            const swallow = (event) => {
                event.stopImmediatePropagation();
                event.preventDefault();
            };
            target.addEventListener('click', swallow, {
                once: true,
                capture: true,
            });
            setTimeout(() => {
                target.removeEventListener('click', swallow, true);
            }, 0);
        };
        this.handleCellClick = (ev) => {
            ev.stopPropagation();
            ev.preventDefault();
        };
        this.releaseDetachedHandles = (node) => {
            if (!(node instanceof HTMLElement)) {
                return;
            }
            const handles = node.matches(LIMEL_DRAG_HANDLE)
                ? [node]
                : [...node.querySelectorAll(LIMEL_DRAG_HANDLE)];
            for (const handle of handles) {
                if (!handle.isConnected) {
                    this.pool.release(handle);
                }
            }
        };
        this.handleRowMoved = this.handleRowMoved.bind(this);
    }
    /**
     * Start releasing drag-handle elements back to the pool when Tabulator
     * virtualizes rows out of view. Safe to call multiple times — a previous
     * observer is disconnected first.
     *
     * @param container - The element that hosts the Tabulator table.
     */
    observe(container) {
        this.destroy();
        this.mutationObserver = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                for (const node of mutation.removedNodes) {
                    this.releaseDetachedHandles(node);
                }
            }
        });
        this.mutationObserver.observe(container, {
            childList: true,
            subtree: true,
        });
    }
    /**
     * Disconnects the mutation observer. Call when the manager is no longer
     * needed (e.g. on `disconnectedCallback` or when `movableRows` is toggled).
     */
    destroy() {
        var _a;
        (_a = this.mutationObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
        this.mutationObserver = null;
    }
    /**
     * Returns the Tabulator rowHeader config that renders
     * a limel-drag-handle and restricts dragging to that cell
     */
    getRowHeaderDefinition() {
        return {
            headerSort: false,
            resizable: false,
            frozen: true,
            rowHandle: true,
            formatter: this.getDragHandleFormatter(),
            cssClass: 'limel-table-drag-handle',
            cellClick: this.handleCellClick,
        };
    }
    /**
     * Tabulator rowMoved event handler.
     * Attach this to the tabulator instance via `tabulator.on('rowMoved', ...)`
     * @param row
     */
    handleRowMoved(row) {
        const prevRow = row.getPrevRow();
        const nextRow = row.getNextRow();
        if (prevRow) {
            this.reorderEvent.emit({
                fromRow: row.getData(),
                toRow: prevRow.getData(),
                above: false,
            });
        }
        else if (nextRow) {
            this.reorderEvent.emit({
                fromRow: row.getData(),
                toRow: nextRow.getData(),
                above: true,
            });
        }
    }
    getDragHandleFormatter() {
        return () => {
            const element = this.pool.get(LIMEL_DRAG_HANDLE);
            setElementProperties(element, {
                dragDirection: 'vertical',
                language: this.getLanguage(),
            });
            return element;
        };
    }
}
