// #region Imports
/**
 * Handles keyboard-based dragging for accessibility.
 *
 * @internal
 */
export class KeyboardDragHandler {
    // #region Fields
    _element;
    _config;
    _position = {
        x: 0,
        y: 0
    };
    _isActive = false;
    _keydownListener = null;
    _callbacks = {};
    // #endregion
    // #region Ctor
    /**
     * Create a new KeyboardDragHandler.
     *
     * @param element - Target element.
     * @param config - Configuration.
     */
    constructor(element, config) {
        this._element = element;
        this._config = this._applyDefaults(config);
    }
    // #endregion
    // #region Properties
    /**
     * Get whether keyboard drag is active.
     *
     * @public
     */
    get isActive() {
        return this._isActive;
    }
    /**
     * Get current position.
     *
     * @public
     */
    get position() {
        return { ...this._position };
    }
    // #endregion
    // #region Methods
    /**
     * Attach keyboard listeners.
     *
     * @param callbacks - Event callbacks.
     *
     * @public
     */
    attach(callbacks) {
        if (!this._config.enabled) {
            return;
        }
        this._callbacks = callbacks;
        this._keydownListener = this._onKeyDown.bind(this);
        this._element.addEventListener('keydown', this._keydownListener);
        // Make element focusable if not already
        if (!this._element.hasAttribute('tabindex')) {
            this._element.setAttribute('tabindex', '0');
        }
        // Add role if not present
        if (!this._element.hasAttribute('role')) {
            this._element.setAttribute('role', 'button');
        }
        // Add ARIA label
        if (!this._element.hasAttribute('aria-label') && !this._element.hasAttribute('aria-labelledby')) {
            this._element.setAttribute('aria-label', 'Draggable item. Press Space to pick up, arrow keys to move, Enter to drop, Escape to cancel.');
        }
    }
    /**
     * Detach keyboard listeners.
     *
     * @public
     */
    detach() {
        if (this._keydownListener) {
            this._element.removeEventListener('keydown', this._keydownListener);
            this._keydownListener = null;
        }
        this._callbacks = {};
    }
    /**
     * Reset position.
     *
     * @public
     */
    reset() {
        this._position = {
            x: 0,
            y: 0
        };
        this._isActive = false;
    }
    // #endregion
    // #region Private Methods
    /**
     * Handle keydown event.
     *
     * @param event - Keyboard event.
     *
     * @private
     */
    _onKeyDown(event) {
        const { key, shiftKey } = event;
        // Space to pick up / put down
        if (key === ' ' || key === 'Spacebar') {
            event.preventDefault();
            this._toggleDrag();
            return;
        }
        // Escape to cancel
        if (key === 'Escape' && this._isActive) {
            event.preventDefault();
            this._endDrag(false);
            return;
        }
        // Enter to drop
        if (key === 'Enter' && this._isActive) {
            event.preventDefault();
            this._endDrag(true);
            return;
        }
        // Arrow keys to move (only when active)
        if (this._isActive && this._isArrowKey(key)) {
            event.preventDefault();
            this._handleArrowKey(key, shiftKey);
        }
    }
    /**
     * Toggle drag state.
     *
     * @private
     */
    _toggleDrag() {
        if (this._isActive) {
            this._endDrag(true);
        }
        else {
            this._startDrag();
        }
    }
    /**
     * Start keyboard drag.
     *
     * @private
     */
    _startDrag() {
        this._isActive = true;
        this._position = {
            x: 0,
            y: 0
        };
        // Update ARIA
        this._element.setAttribute('aria-grabbed', 'true');
        // Announce to screen readers
        this._announce('Picked up. Use arrow keys to move, Enter to drop, Escape to cancel.');
        // Callback
        this._callbacks.onStart?.();
    }
    /**
     * End keyboard drag.
     *
     * @param dropped - Whether item was dropped (true) or cancelled (false).
     *
     * @private
     */
    _endDrag(dropped) {
        this._isActive = false;
        // Update ARIA
        this._element.setAttribute('aria-grabbed', 'false');
        // Announce to screen readers
        if (dropped) {
            this._announce('Dropped.');
        }
        else {
            this._announce('Cancelled.');
        }
        // Callback
        this._callbacks.onEnd?.(dropped);
        // Reset position
        this._position = {
            x: 0,
            y: 0
        };
    }
    /**
     * Handle arrow key press.
     *
     * @param key - Arrow key.
     * @param shiftKey - Whether Shift is held.
     *
     * @private
     */
    _handleArrowKey(key, shiftKey) {
        const step = this._config.stepSize * (shiftKey ? this._config.shiftMultiplier : 1);
        const delta = {
            x: 0,
            y: 0
        };
        switch (key) {
            case 'ArrowLeft':
                delta.x = -step;
                break;
            case 'ArrowRight':
                delta.x = step;
                break;
            case 'ArrowUp':
                delta.y = -step;
                break;
            case 'ArrowDown':
                delta.y = step;
                break;
        }
        this._position.x += delta.x;
        this._position.y += delta.y;
        // Callback
        this._callbacks.onMove?.(delta);
        // Announce movement to screen readers
        this._announce(`Moved ${delta.x !== 0 ? delta.x > 0 ? 'right' : 'left' : delta.y > 0 ? 'down' : 'up'}`);
    }
    /**
     * Check if key is an arrow key.
     *
     * @param key - Key name.
     * @returns True if arrow key.
     *
     * @private
     */
    _isArrowKey(key) {
        return ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(key);
    }
    /**
     * Announce message to screen readers.
     *
     * @param message - Message to announce.
     *
     * @private
     */
    _announce(message) {
        // Check if live region exists
        let liveRegion = document.querySelector('[data-drag-live-region]');
        if (!liveRegion) {
            // Create live region
            liveRegion = document.createElement('div');
            liveRegion.setAttribute('data-drag-live-region', '');
            liveRegion.setAttribute('aria-live', 'assertive');
            liveRegion.setAttribute('aria-atomic', 'true');
            liveRegion.style.position = 'absolute';
            liveRegion.style.left = '-10000px';
            liveRegion.style.width = '1px';
            liveRegion.style.height = '1px';
            liveRegion.style.overflow = 'hidden';
            document.body.appendChild(liveRegion);
        }
        // Update content to trigger announcement
        liveRegion.textContent = message;
    }
    /**
     * Apply default config values.
     *
     * @param config - User config.
     * @returns Full config.
     *
     * @private
     */
    _applyDefaults(config) {
        return {
            stepSize: config?.stepSize ?? 10,
            shiftMultiplier: config?.shiftMultiplier ?? 5,
            enabled: config?.enabled ?? true
        };
    }
}
// #endregion
//# sourceMappingURL=KeyboardDragHandler.js.map