/**
 * @file assets/js/adminjs/admin-formatting.js
 * @description My Book Showroom — Formatting Tab JavaScript
 *
 * Handles two UI behaviors on the Settings → Formatting tab:
 *
 *   1. Layout thumbnail ↔ dropdown bidirectional sync
 *      · Clicking a non-disabled .mbs-layout-thumbnail updates the
 *        #mbs_setting_formatting_default_layout dropdown and visually
 *        marks that thumbnail as .is-selected (plus aria-checked=true).
 *      · Changing the dropdown updates the selected thumbnail's visual state.
 *      · PRO thumbnails on FREE tier render with .is-disabled and
 *        disabled=true — clicks are ignored so the dropdown cannot end up
 *        on a PRO layout for a FREE user.
 *
 *   2. Merge-tag pill insertion at textarea cursor (PRO only)
 *      · Clicking .mbs-merge-tag-pill inserts the pill's data-tag value at
 *        the current cursor position of the textarea identified by its
 *        container's data-target selector. Preserves existing content,
 *        maintains cursor position after the insert, and triggers a
 *        native 'input' event so unsaved-changes trackers (if any) notice.
 *
 * This script is enqueued by MBS_Settings::enqueue_assets() only when
 * $current_tab === 'formatting'. No external dependencies beyond jQuery.
 *
 * @package    My_Book_Showroom
 * @subpackage Assets/JS/AdminJS
 * @since      1.0.0
 */

( function ( $ ) {
	'use strict';
	var __ = wp.i18n.__;

	// ── 1. Layout thumbnail ↔ dropdown sync ──────────────────────────────

	function initLayoutThumbnails() {
		var $dropdown   = $( '#mbs_setting_formatting_default_layout' );
		var $thumbnails = $( '.mbs-layout-thumbnail' );

		if ( ! $dropdown.length || ! $thumbnails.length ) {
			return;
		}

		/**
		 * Apply the .is-selected class (and aria-checked) to the thumbnail
		 * matching the dropdown's current value. Clears it from all others.
		 */
		function syncSelectionFromDropdown() {
			var value = $dropdown.val();
			$thumbnails.each( function () {
				var $t        = $( this );
				var isMatch   = $t.data( 'layout' ) === value;
				$t.toggleClass( 'is-selected', isMatch );
				$t.attr( 'aria-checked', isMatch ? 'true' : 'false' );
			} );
		}

		// Dropdown → thumbnails
		$dropdown.on( 'change', syncSelectionFromDropdown );

		// Thumbnails → dropdown
		$thumbnails.on( 'click', function ( e ) {
			e.preventDefault();

			var $t = $( this );
			if ( $t.prop( 'disabled' ) || $t.hasClass( 'is-disabled' ) ) {
				return;
			}

			var slug = $t.data( 'layout' );
			if ( ! slug ) {
				return;
			}

			if ( $dropdown.val() !== slug ) {
				$dropdown.val( slug ).trigger( 'change' );
			} else {
				// Value already matches — still re-apply visual state in case
				// the DOM is out of sync with the dropdown.
				syncSelectionFromDropdown();
			}
		} );

		// Keyboard accessibility: radiogroup semantics — space/enter selects.
		$thumbnails.on( 'keydown', function ( e ) {
			if ( e.key === ' ' || e.key === 'Enter' ) {
				e.preventDefault();
				$( this ).trigger( 'click' );
			}
		} );
	}

	// ── 2. Merge-tag pills → textarea cursor insert ──────────────────────

	function initMergeTagPills() {
		$( '.mbs-merge-tag-pills' ).each( function () {
			var $container = $( this );
			var targetSel  = $container.data( 'target' );
			if ( ! targetSel ) {
				return;
			}

			var $textarea = $( targetSel );
			if ( ! $textarea.length ) {
				return;
			}

			$container.on( 'click', '.mbs-merge-tag-pill', function ( e ) {
				e.preventDefault();

				if ( $textarea.prop( 'disabled' ) ) {
					return;
				}

				var tag = $( this ).data( 'tag' );
				if ( ! tag ) {
					return;
				}

				insertAtCursor( $textarea[ 0 ], String( tag ) );
				$textarea.trigger( 'focus' );
			} );
		} );
	}

	/**
	 * Insert `text` at the current cursor position of the given <textarea>
	 * (or <input>) DOM element. Preserves existing content outside the
	 * selection, replaces any selected range with the tag, and positions
	 * the cursor immediately after the inserted text.
	 *
	 * Falls back to appending when selectionStart is not available (older
	 * browsers / detached inputs).
	 *
	 * @param {HTMLTextAreaElement|HTMLInputElement} el
	 * @param {string} text
	 */
	function insertAtCursor( el, text ) {
		if ( typeof el.selectionStart !== 'number' ) {
			el.value += text;
			return;
		}

		var start  = el.selectionStart;
		var end    = el.selectionEnd;
		var before = el.value.substring( 0, start );
		var after  = el.value.substring( end );

		el.value = before + text + after;

		var caret = start + text.length;
		el.selectionStart = caret;
		el.selectionEnd   = caret;

		// Fire a native 'input' event so any change-tracking listeners
		// (e.g. unsaved-changes warnings) see the mutation.
		if ( typeof Event === 'function' ) {
			el.dispatchEvent( new Event( 'input', { bubbles: true } ) );
		} else {
			// IE11 fallback — not expected in WP admin but defensive.
			var evt = document.createEvent( 'Event' );
			evt.initEvent( 'input', true, true );
			el.dispatchEvent( evt );
		}
	}

	// ── 3. Live layout preview (Story 14-7) ─────────────────────────────

	function initLayoutPreview() {
		var $dropdown  = $( '#mbs_setting_formatting_default_layout' );
		var $wrap      = $( '#mbs-layout-preview-wrap' );
		var $frame     = $( '#mbs-layout-preview-frame' );
		var $status    = $( '#mbs-layout-preview-status' );
		var frameEl    = $frame[ 0 ];
		var previewXhr = null;

		if ( ! $dropdown.length || ! $wrap.length || ! $frame.length ) {
			return; // Preview DOM not present on this page — exit silently.
		}

		// Guard: MBS_LayoutPreview must be localised by MBS_Layout_Preview::localize_nonce().
		if ( typeof MBS_LayoutPreview === 'undefined' || ! MBS_LayoutPreview.nonce ) {
			return;
		}

		function fetchPreview( slug ) {
			if ( ! slug ) {
				return;
			}

			// Abort any in-flight request.
			if ( previewXhr ) {
				previewXhr.abort();
				previewXhr = null;
			}

			$status.text( __( 'Loading preview\u2026', 'my-book-showroom' ) ).show();
			$wrap.show();

			previewXhr = $.post(
				MBS_LayoutPreview.ajaxurl,
				{
					action: 'mbs_layout_preview',
					nonce:  MBS_LayoutPreview.nonce,
					layout: slug,
				},
				function ( res ) {
					previewXhr = null;
					$status.hide();

					if ( ! res.success || ! res.data || ! res.data.html ) {
						$status.text( __( 'Preview failed. Please try again.', 'my-book-showroom' ) ).show();
						return;
					}

					// ── srcdoc injection ──────────────────────────────────
					// Set via DOM property (not setAttribute) — the browser uses
					// the raw HTML string directly as the iframe document source.
					// srcdoc isolation prevents any XSS from the preview content
					// from affecting the parent admin document.
					// We do NOT use innerHTML on the parent document. (SEC-02)
					frameEl.srcdoc = res.data.html;
				}
			).fail( function ( xhr ) {
				previewXhr = null;
				if ( 'abort' === xhr.statusText ) {
					return; // Intentional — another request superseded this one.
				}
				$status.text( __( 'Preview unavailable. Server error.', 'my-book-showroom' ) ).show();
			} );
		}

		// Trigger a preview whenever the layout dropdown value changes.
		// This piggybacks on the existing 'change' listener in initLayoutThumbnails().
		$dropdown.on( 'change.mbs-preview', function () {
			fetchPreview( $( this ).val() );
		} );

		// Load a preview for the currently selected layout on page load.
		var initialSlug = $dropdown.val();
		if ( initialSlug ) {
			fetchPreview( initialSlug );
		}
	}

	// ── Init on DOM ready ────────────────────────────────────────────────

	$( document ).ready( function () {
		initLayoutThumbnails();
		initMergeTagPills();
		initLayoutPreview();

		// Wire the global default layout dropdown to the description panel.
		// mbs-admin-layout-desc.js (dependency) exposes window.MBS_LayoutDesc.
		if ( typeof MBS_LayoutDesc !== 'undefined' ) {
			MBS_LayoutDesc.init(
				'#mbs_setting_formatting_default_layout',
				'#mbs-layout-description'
			);
		}
	} );

} )( jQuery );
