(function (window, $) {
	'use strict';

	if (!$ || !window) {
		return;
	}

	var HANDLE_CLASS = 'wpps-reorder-lt-handle';

	function strings(config, key) {
		return (config.strings && config.strings[key]) || '';
	}

	function showToast(message, type) {
		var $toast = $('.wpps-reorder-list-table-toast');
		if (!$toast.length) {
			$toast = $('<div class="wpps-reorder-list-table-toast" role="status" aria-live="polite"></div>');
			$('body').append($toast);
		}
		$toast.text(message || '').removeClass('is-visible');
		if (type === 'error') {
			$toast.css('background', '#d63638');
		} else {
			$toast.css('background', '#1d2327');
		}
		window.requestAnimationFrame(function () {
			$toast.addClass('is-visible');
		});
		window.setTimeout(function () {
			$toast.removeClass('is-visible');
		}, 2600);
	}

	window.wppsOrderingUi = {
		showToast: showToast,

		initListTable: function (options) {
			var config = options.config || {};
			var $tbody = $(options.tbodySelector || '#the-list');
			if (!$tbody.length) {
				return;
			}

			$('body').addClass('wpps-reorder-list-table');
			var saving = false;
			var handleLabel = strings(config, 'dragHandle') || 'Drag to reorder';

			function addHandle(row) {
				var $row = $(row);
				if (!$row.is('tr') || $row.find('.' + HANDLE_CLASS).length) {
					return;
				}
				if (!options.extractId($row)) {
					return;
				}

				// A <span> (not a <button>) is used deliberately: jQuery UI sortable's
				// default `cancel` selector blocks drags started on form elements, so a
				// button handle would silently refuse to drag.
				var $handle = $('<span class="' + HANDLE_CLASS + '"></span>')
					.attr('aria-label', handleLabel)
					.attr('title', handleLabel)
					.append('<span class="dashicons dashicons-menu" aria-hidden="true"></span>');

				// Place the handle inline, immediately before the row title so it reads
				// as "[grip] Title" rather than sitting on its own line above it.
				var $title = $row.find('.row-title').first();
				if ($title.length) {
					$handle.insertBefore($title);
					return;
				}

				var $cell = $row.find('td.column-primary, th.column-primary').first();
				if (!$cell.length) {
					$cell = $row.children('td, th').not('.check-column').first();
				}
				if ($cell.length) {
					$handle.prependTo($cell);
				}
			}

			function addHandles() {
				$tbody.children('tr').each(function () {
					addHandle(this);
				});
			}

			function collectOrder() {
				return $tbody.children('tr').map(function () {
					return options.extractId($(this));
				}).get().filter(function (id) { return !!id; });
			}

			function saveOrder() {
				if (saving) {
					return;
				}

				var allOrder = collectOrder();
				var chunkSize = (config.settings && config.settings.chunkSize) || 50;
				var chunks = [];
				var idx;

				for (idx = 0; idx < allOrder.length; idx += chunkSize) {
					chunks.push(allOrder.slice(idx, idx + chunkSize));
				}

				if (!chunks.length) {
					return;
				}

				saving = true;
				var chunkIndex = 0;

				function saveNextChunk() {
					if (chunkIndex >= chunks.length) {
						return;
					}

					$.post(config.ajaxUrl, $.extend({
						action: options.actions.save,
						nonce: config.nonce,
						order: chunks[chunkIndex],
						order_offset: chunkIndex * chunkSize,
						is_chunk: chunks.length > 1 ? 1 : 0
					}, options.buildPayload()))
						.done(function (response) {
							if (!response || !response.success) {
								saving = false;
								showToast((response && response.data && response.data.message) || strings(config, 'orderSaveFailed'), 'error');
								return;
							}
							chunkIndex += 1;
							if (chunkIndex >= chunks.length) {
								saving = false;
								showToast(response.data.message || strings(config, 'orderSaved'));
								return;
							}
							saveNextChunk();
						})
						.fail(function () {
							saving = false;
							showToast(strings(config, 'orderSaveFailed'), 'error');
						});
				}

				saveNextChunk();
			}

			addHandles();

			if ($tbody.sortable) {
				$tbody.sortable({
					items: options.itemsSelector || '> tr',
					axis: 'y',
					handle: options.handleSelector || '.' + HANDLE_CLASS,
					placeholder: 'wpps-reorder-lt-placeholder',
					forcePlaceholderSize: true,
					helper: function (_event, ui) {
						ui.children().each(function () {
							$(this).width($(this).width());
						});
						return ui;
					},
					start: function (_event, ui) {
						ui.item.addClass('wpps-reorder-lt-dragging');
					},
					stop: function (_event, ui) {
						ui.item.removeClass('wpps-reorder-lt-dragging');
					},
					update: saveOrder
				});

				// Re-add handles to rows replaced by inline "Quick Edit" and keep
				// the sortable list aware of any new rows.
				if (typeof window.MutationObserver !== 'undefined') {
					var observer = new window.MutationObserver(function (mutations) {
						var changed = false;
						mutations.forEach(function (mutation) {
							Array.prototype.forEach.call(mutation.addedNodes, function (node) {
								if (node.nodeType === 1 && node.tagName === 'TR') {
									addHandle(node);
									changed = true;
								}
							});
						});
						if (changed && $tbody.hasClass('ui-sortable')) {
							$tbody.sortable('refresh');
						}
					});
					observer.observe($tbody.get(0), { childList: true });
				}
			}
		}
	};
})(window, window.jQuery);
