/**
 * CartCue — Undo bar.
 *
 * Two surfaces:
 *  1. PLAY DELETE: after handle_delete_play() runs, the BuildFeatures bootstrap
 *     appends ?cartcue_undo_id=N to the redirect URL when a transient snapshot
 *     exists. On page load we detect this query arg, show the toast, and on
 *     click POST to wp_ajax_cartcue_undo_delete_play to restore the row.
 *
 *  2. SEQUENCE STEP DELETE / RULE DELETE: pure client-side undo — we intercept
 *     the click on .ap-remove-action / .ap-remove-rule, stash the removed DOM
 *     node in memory, show the toast, and re-insert if the user clicks Undo
 *     within 5 seconds.
 */
(function ($) {
	'use strict';

	var cfg     = (window.cartcueAdmin && cartcueAdmin.buildFeatures) || {};
	var strings = cfg.strings || {};

	// -------------------------------------------------------------------
	// Toast UI
	// -------------------------------------------------------------------

	function ensureToast() {
		var $t = $('#ap-undo-toast');
		if ($t.length) { return $t; }
		$t = $(
			'<div id="ap-undo-toast" class="ap-undo-toast" role="status" aria-live="polite" hidden>' +
				'<span class="ap-undo-toast__msg" data-undo-msg></span>' +
				'<button type="button" class="ap-undo-toast__btn" data-undo-btn></button>' +
				'<button type="button" class="ap-undo-toast__close" data-undo-close aria-label="Dismiss">×</button>' +
				'<span class="ap-undo-toast__bar"><span class="ap-undo-toast__bar-fill" data-undo-bar></span></span>' +
			'</div>'
		);
		$('body').append($t);
		return $t;
	}

	/**
	 * Show toast for ms milliseconds. onUndo runs if the user clicks Undo
	 * before timeout. onTimeout runs if it expires.
	 */
	function showUndo(message, ms, onUndo, onTimeout) {
		var $t = ensureToast();
		$t.find('[data-undo-msg]').text(message);
		$t.find('[data-undo-btn]').text(strings.undoLabel || 'Undo');
		$t.attr('hidden', false).removeClass('is-leaving').addClass('is-open');
		$t.find('[data-undo-bar]').css({ width: '100%', transition: 'none' });
		// kick off the bar drain
		requestAnimationFrame(function () {
			$t.find('[data-undo-bar]').css({
				width: '0%',
				transition: 'width ' + ms + 'ms linear'
			});
		});

		var undone = false;
		var timer = setTimeout(function () {
			if (undone) { return; }
			hide();
			if (typeof onTimeout === 'function') { onTimeout(); }
		}, ms);

		function hide() {
			$t.addClass('is-leaving').removeClass('is-open');
			setTimeout(function () { $t.attr('hidden', true); }, 220);
			$t.off('click', '[data-undo-btn], [data-undo-close]');
		}

		$t.off('click', '[data-undo-btn], [data-undo-close]')
		  .on('click', '[data-undo-btn]', function () {
			undone = true;
			clearTimeout(timer);
			hide();
			if (typeof onUndo === 'function') { onUndo(); }
		  })
		  .on('click', '[data-undo-close]', function () {
			clearTimeout(timer);
			hide();
		  });
	}

	// -------------------------------------------------------------------
	// 1. Play deletion undo (server-side restore)
	// -------------------------------------------------------------------

	function detectDeletedPlay() {
		var params = new URLSearchParams(window.location.search);
		var id = parseInt(params.get('cartcue_undo_id') || '0', 10);
		if (!id) { return; }

		// Strip the param from the URL so a refresh doesn't reshow the toast.
		if (window.history && history.replaceState) {
			params.delete('cartcue_undo_id');
			var clean = window.location.pathname + (params.toString() ? '?' + params.toString() : '');
			history.replaceState({}, '', clean);
		}

		showUndo(
			strings.undoDeleted || 'Automation removed.',
			60000, // 60 second window
			function onUndo() {
				$.post(cartcueAdmin.ajaxUrl, {
					action: 'cartcue_undo_delete_play',
					nonce:  cfg.undoNonce,
					id:     id
				}).done(function (res) {
					if (res && res.success) {
						showFlash(strings.undoRestored || 'Restored.', 'ok');
						// Soft reload so the restored play shows up.
						setTimeout(function () { window.location.reload(); }, 600);
					} else {
						showFlash((res && res.data && res.data.msg) || strings.undoFailed || 'Could not undo.', 'err');
					}
				}).fail(function () {
					showFlash(strings.undoFailed || 'Could not undo.', 'err');
				});
			}
		);
	}

	// Tiny inline flash for restored/failed feedback (we don't reuse the undo toast).
	function showFlash(text, kind) {
		var $f = $('<div class="ap-undo-flash" data-kind="' + (kind || '') + '"></div>').text(text);
		$('body').append($f);
		requestAnimationFrame(function () { $f.addClass('is-open'); });
		setTimeout(function () {
			$f.removeClass('is-open');
			setTimeout(function () { $f.remove(); }, 220);
		}, 2400);
	}

	// -------------------------------------------------------------------
	// 2. Sequence step / rule / action undo (client-side stash)
	// -------------------------------------------------------------------

	function clientSideUndo($removedNode, $insertAnchor, where, friendlyName) {
		// where = 'before' | 'after' | 'append'
		showUndo(
			(friendlyName || 'Step') + ' removed.',
			5000,
			function onUndo() {
				if (where === 'before')      { $insertAnchor.before($removedNode); }
				else if (where === 'after')  { $insertAnchor.after($removedNode);  }
				else                          { $insertAnchor.append($removedNode); }
				$removedNode.hide().slideDown(180);
				// re-trigger story refresh hooks that the original removers fire.
				$(document).trigger('cartcue:undo-restored', [$removedNode]);
			}
		);
	}

	function bindClientUndo(selector, friendlyName) {
		// We intercept by binding at capture phase via .on(),
		// but the existing handlers also remove the node. So we clone-then-let-remove-happen.
		$(document).on('click', selector, function (e) {
			var $node = $(e.currentTarget).closest('.ap-action-card, .ap-rule-row, .ap-sequence-step');
			if (!$node.length) { return; }

			// Snapshot of the node *and* its surrounding position.
			var $clone   = $node.clone(true, true);  // include event handlers
			var $prev    = $node.prev();
			var $parent  = $node.parent();
			var where    = $prev.length ? 'after' : 'append';
			var anchor   = $prev.length ? $prev   : $parent;

			// Defer until existing handlers have done their removal,
			// then expose the undo bar.
			setTimeout(function () {
				clientSideUndo($clone, anchor, where, friendlyName);
			}, 30);
		});
	}

	$(function () {
		detectDeletedPlay();

		// Wire client-side undo for the in-editor remove buttons.
		bindClientUndo('.ap-remove-action',   'Action');
		bindClientUndo('.ap-remove-rule',     'Filter');
		bindClientUndo('.ap-remove-seq-step', 'Step');
	});

})(jQuery);
