/**
 * File Path: assets/js/adminjs/mbs-sortable-list.js
 *
 * MBS.SortableList -- Reusable drag-and-drop sort factory.
 *
 * Generalises the sort-control pattern used across the plugin admin UI:
 * jQuery UI Sortable (PRO, when the drag handle is present in the DOM) with a
 * disabled-boundary up/down arrow fallback (FREE tier and no-JS).
 *
 * PHP counterpart  : includes/helpers/class-mbs-sortable-ui.php (MBS_Sortable_UI).
 * Stylesheet       : assets/css/admin/mbs-sortable.css
 *
 * Handle: mbs-sortable-list
 * Deps  : jquery, jquery-ui-sortable, mbs-admin-utils
 *
 * @package    My_Book_Showroom
 * @since      1.4.0
 */
;(function( MBS, $ ) {
	'use strict';

	/**
	 * @namespace MBS.SortableList
	 */
	MBS.SortableList = {

		/**
		 * Create a sortable list instance.
		 *
		 * Initializes jQuery UI Sortable when the drag handle is present (PRO tier)
		 * and hides the up/down fallback controls. Falls back to arrow-button sort
		 * (all tiers, no-JS) when the handle is absent or Sortable is unavailable.
		 *
		 * @param {Object}   config
		 * @param {string}   config.container         Selector for the sortable list container.
		 * @param {string}   config.itemSelector      Selector for sortable items inside container.
		 * @param {string}   config.handleSelector    Selector for the drag-handle span.
		 *                                            Absence in the DOM means FREE tier -- no drag.
		 * @param {string}   config.controlsSelector  Selector for the up/down fallback wrapper.
		 * @param {string}   config.upSelector        Selector for the move-up button.
		 * @param {string}   config.downSelector      Selector for the move-down button.
		 * @param {string}   [config.placeholderClass] CSS class for the drag placeholder. Default:
		 *                                            'mbs-sortable-placeholder'.
		 * @param {Function} [config.onReorder]       Callback invoked after every reorder action.
		 *                                            Receives the $container jQuery object.
		 * @returns {{ refreshButtons: function, usingDrag: function, destroy: function }}
		 * @since 1.4.0
		 */
		create: function( config ) {
			var $container       = $( config.container );
			var itemSel          = config.itemSelector;
			var handleSel        = config.handleSelector;
			var controlsSel      = config.controlsSelector;
			var upSel            = config.upSelector;
			var downSel          = config.downSelector;
			var placeholderClass = config.placeholderClass || 'mbs-sortable-placeholder';
			var onReorder        = typeof config.onReorder === 'function' ? config.onReorder : null;
			var usingSortable    = false;

			if ( ! $container.length ) {
				return { refreshButtons: function() {}, usingDrag: function() { return false; }, destroy: function() {} };
			}

			/**
			 * Disable the Up button on the first item and Down on the last.
			 * Re-enables all others. Call after any DOM change.
			 *
			 * @returns {void}
			 */
			function refreshButtons() {
				var $items = $container.find( itemSel );
				$items.find( upSel ).prop( 'disabled', false );
				$items.find( downSel ).prop( 'disabled', false );
				$items.first().find( upSel ).prop( 'disabled', true );
				$items.last().find( downSel ).prop( 'disabled', true );
			}

			/**
			 * Invoke the onReorder callback.
			 *
			 * @returns {void}
			 */
			function notifyReorder() {
				if ( onReorder ) {
					onReorder( $container );
				}
			}

			if ( typeof $.fn.sortable !== 'undefined' && $container.find( handleSel ).length ) {

				// ── PRO path: jQuery UI Sortable ─────────────────────────────────
				$container.sortable( {
					items:                itemSel,
					handle:               handleSel,
					axis:                 'y',
					tolerance:            'pointer',
					placeholder:          placeholderClass,
					forcePlaceholderSize: true,
					stop: function() {
						notifyReorder();
					}
				} );

				// Drag is active -- hide arrow fallback on all existing items.
				$container.find( controlsSel ).hide();
				usingSortable = true;

			} else {

				// ── FREE / no-JS path: up/down arrow buttons ─────────────────────
				refreshButtons();

				$container.on( 'click', upSel, function( e ) {
					e.preventDefault();
					var $item = $( this ).closest( itemSel );
					var $prev = $item.prev( itemSel );
					if ( $prev.length ) {
						$item.insertBefore( $prev );
						refreshButtons();
						notifyReorder();
					}
				} );

				$container.on( 'click', downSel, function( e ) {
					e.preventDefault();
					var $item = $( this ).closest( itemSel );
					var $next = $item.next( itemSel );
					if ( $next.length ) {
						$item.insertAfter( $next );
						refreshButtons();
						notifyReorder();
					}
				} );
			}

			return {

				/**
				 * Refresh boundary button disabled states.
				 * Call after programmatically adding or removing items.
				 *
				 * @returns {void}
				 */
				refreshButtons: refreshButtons,

				/**
				 * Returns true if jQuery UI Sortable is active on this list.
				 *
				 * @returns {boolean}
				 */
				usingDrag: function() {
					return usingSortable;
				},

				/**
				 * Refresh the jQuery UI Sortable widget after items are added or removed.
				 * Also hides the fallback controls on new items when drag is active.
				 * No-op when using arrow fallback.
				 *
				 * @returns {void}
				 */
				refresh: function() {
					if ( usingSortable && typeof $.fn.sortable !== 'undefined' ) {
						$container.sortable( 'refresh' );
						$container.find( controlsSel ).hide();
					} else {
						refreshButtons();
					}
				},

				/**
				 * Tear down sortable and delegated event handlers.
				 *
				 * @returns {void}
				 */
				destroy: function() {
					if ( usingSortable && typeof $.fn.sortable !== 'undefined' ) {
						$container.sortable( 'destroy' );
					}
					$container.off( 'click', upSel );
					$container.off( 'click', downSel );
				}
			};
		}
	};

})( window.MBS = window.MBS || {}, jQuery );
