/**
 * Applies effects in Canvas, after changing some settings in the right sidebar in BFB.
 *
 * @file ../includes/page-form-builder/form-settings/_src/settings_effects.js
 */
(function (w, d) {
	'use strict';

	const Effects = (w.WPBC_BFB_Settings_Effects = w.WPBC_BFB_Settings_Effects || {});
	const map     = (Effects.map = Effects.map || Object.create( null ));

	Effects.register = function (key, fn) {
		if ( key && typeof fn === 'function' ) {
			map[String( key )] = fn;
		}
	};

	function get_canvas_root() {
		return (
			d.querySelector( '#wpbc_bfb__pages_container' ) ||
			d.querySelector( '.wpbc_bfb__panel--preview' ) ||
			d.getElementById( 'wpbc_bfb__preview' ) ||
			d.body || d.documentElement
		);
	}

	Effects.apply_one = function (key, value, ctx) {
		const fn = map[String( key )];
		if ( ! fn ) {
			return;
		}
		try {
			fn( value, Object.assign( { key, value, canvas: get_canvas_root() }, ctx || {} ) );
		} catch ( e ) {
			// keep silent in production if you prefer
			console.error( 'WPBC Effects error:', key, e );
		}
	};

	Effects.apply_all = function (options, ctx) {
		if ( ! options || typeof options !== 'object' ) {
			return;
		}
		Object.keys( options ).forEach( function (k) {
			Effects.apply_one( k, options[k], ctx );
		} );
	};

	/**
	 * Normalize settings pack to the minimum required shape:
	 * { options: {}, css_vars: {} }
	 *
	 * @param {*} pack
	 * @return {{options:Object, css_vars:Object, bfb_options?:Object}|null}
	 */
	Effects.normalize_pack = function (pack) {

		if ( pack === null || typeof pack === 'undefined' || pack === '' ) {
			return null;
		}

		// Parse JSON string if needed.
		if ( typeof pack === 'string' ) {
			try {
				pack = JSON.parse( pack );
			} catch ( _e ) {
				return null;
			}
		}

		if ( ! pack || typeof pack !== 'object' ) {
			return null;
		}

		// If user passed just {key:value} options map, wrap it.
		const has_shape =
				  Object.prototype.hasOwnProperty.call( pack, 'options' ) ||
				  Object.prototype.hasOwnProperty.call( pack, 'css_vars' ) ||
				  Object.prototype.hasOwnProperty.call( pack, 'bfb_options' );

		if ( ! has_shape ) {
			pack = { options: pack, css_vars: {} };
		}

		if ( ! pack.options || typeof pack.options !== 'object' ) {
			pack.options = {};
		}
		if ( ! pack.css_vars || typeof pack.css_vars !== 'object' ) {
			pack.css_vars = {};
		}

		// bfb_options is optional; keep if valid.
		if ( pack.bfb_options && typeof pack.bfb_options !== 'object' ) {
			delete pack.bfb_options;
		}

		return pack;
	};

	/**
	 * Re-apply settings effects after a canvas rebuild / structure load.
	 *
	 * This is needed because structure loading can replace DOM nodes that effects target.
	 *
	 * @param {*} settings_pack  string|object settings_json pack (or plain options map)
	 * @param {Object} [ctx]
	 */
	Effects.reapply_after_canvas = function (settings_pack, ctx) {

		const pack = Effects.normalize_pack( settings_pack );
		if ( ! pack ) {
			return;
		}

		// Apply immediately (best effort).
		Effects.apply_all( pack.options, Object.assign( { source: 'reapply_after_canvas' }, ctx || {} ) );

		// Some modules/hydration may run shortly after; do one more pass.
		setTimeout( function () {
			Effects.apply_all( pack.options, Object.assign( { source: 'reapply_after_canvas_delayed' }, ctx || {} ) );
		}, 60 );
	};

	// 1) Apply from AJAX load.
	d.addEventListener( 'wpbc:bfb:form_settings:apply', function (e) {
		const pack = e && e.detail ? e.detail.settings : null;
		if ( pack && pack.options ) {
			Effects.apply_all( pack.options, { source: 'apply' } );
		}
	} );

	// 2) Apply live from UI change (delegated).
	function css_escape(value) {
		const v = String( value == null ? '' : value );
		if ( w.CSS && typeof w.CSS.escape === 'function' ) {
			return w.CSS.escape( v );
		}
		return v.replace( /[^a-zA-Z0-9_\-]/g, '\\$&' );
	}

	function find_fs_root(el) {
		if ( ! el || ! el.closest ) {
			return null;
		}

		// 1) Direct: element or ancestor carries FS key (input/select/textarea writer, radio wrapper, etc.)
		const direct = el.closest( '[data-wpbc-bfb-fs-key]' );
		if ( direct ) {
			return direct;
		}

		// 2) Length: event came from number/unit/range inside .wpbc_slider_len_group
		const len_group = el.closest( '.wpbc_slider_len_group' );
		if ( len_group ) {
			return (
				len_group.querySelector( 'input[data-wpbc_slider_len_writer][data-wpbc-bfb-fs-key]' ) ||
				len_group.querySelector( 'input[data-wpbc-bfb-fs-type="length"][data-wpbc-bfb-fs-key]' ) ||
				null
			);
		}

		// 3) Range: event came from range input inside .wpbc_slider_range_group
		const range_group = el.closest( '.wpbc_slider_range_group' );
		if ( range_group ) {
			return (
				range_group.querySelector( 'input[data-wpbc_slider_range_writer][data-wpbc-bfb-fs-key]' ) ||
				range_group.querySelector( 'input[data-wpbc_slider_range_writer]' ) ||
				null
			);
		}

		return null;
	}

	function read_value_from_fs_root(fs_root, original_target) {
		if ( ! fs_root ) {
			return '';
		}

		const fs_type = String( fs_root.getAttribute( 'data-wpbc-bfb-fs-type' ) || '' );

		// RADIO: read checked within wrapper.
		if ( fs_type === 'radio' ) {
			const control_id = fs_root.getAttribute( 'data-wpbc-bfb-fs-controlid' ) || '';
			const selector   = control_id
				? 'input[type="radio"][name="' + css_escape( control_id ) + '"]:checked'
				: 'input[type="radio"]:checked';

			const checked = fs_root.querySelector( selector );
			return checked ? String( checked.value || '' ) : '';
		}

		// CHECKBOX / TOGGLE
		if ( (original_target && original_target.type === 'checkbox') || fs_root.type === 'checkbox' ) {
			const cb = (original_target && original_target.type === 'checkbox') ? original_target : fs_root;
			return cb.checked ? 'On' : 'Off';
		}

		// DEFAULT: writer/input/textarea/select
		if ( fs_root.value != null ) {
			return String( fs_root.value );
		}
		if ( original_target && original_target.value != null ) {
			return String( original_target.value );
		}

		return '';
	}

	function on_change(ev) {
		// Ignore events dispatched by code (apply/reapply, slider sync, etc.). Effects should react only to real user input + explicit wpbc:bfb:form_settings:apply.
		if ( ev && ev.isTrusted === false ) { return; }
		const target = ev && ev.target;
		if ( ! target ) { return; }

		const fs_root = find_fs_root( target );
		if ( ! fs_root ) { return; }


		// Normalize events so each control produces exactly one effect call.
		// - toggle/select/radio/checkbox => "change" only.
		// - everything else              => "input" only.
		const fs_type = String( fs_root.getAttribute( 'data-wpbc-bfb-fs-type' ) || '' );
		const tag     = String( target.tagName || '' ).toLowerCase();
		const type    = String( target.type || '' ).toLowerCase();

		const use_change = (fs_type === 'toggle') || (fs_type === 'select') || (fs_type === 'radio') || (type === 'checkbox') || (type === 'radio') || (tag === 'select');

		if ( use_change && ev.type !== 'change' ) { return; }
		if ( ! use_change && ev.type !== 'input' ) { return; }
		// -------------------------------------------------------------------------------------------

		const key = fs_root.getAttribute( 'data-wpbc-bfb-fs-key' );
		if ( ! key ) { return; }

		const scope = fs_root.getAttribute( 'data-wpbc-bfb-fs-scope' ) || '';
		const value = read_value_from_fs_root( fs_root, target );

		Effects.apply_one( key, value, { source: 'ui', scope: scope, control: target, fs_root: fs_root } );
	}

	d.addEventListener( 'input', on_change, false );
	d.addEventListener( 'change', on_change, false );

})( window, document );


// BOOKING_FORM_THEME.
WPBC_BFB_Settings_Effects.register( 'booking_form_theme', function (value, ctx) {
	// const root = ctx.canvas;
	const root = document.getElementById( 'wpbc_bfb__theme_scope' );
	if ( ! root || ! root.querySelectorAll ) {
		return;
	}

	// const wraps = root.querySelectorAll( '.wpbc_container.wpbc_form' );
	const wraps = root.querySelectorAll( '.wpbc_bfb__pages_panel' );
	if ( ! wraps.length ) {
		return;
	}

	wraps.forEach( function (wrap) {
		// remove any previous theme classes (simple + future-proof).
		Array.from( wrap.classList ).forEach( function (cls) {
			if ( /^wpbc_theme_/.test( cls ) ) {
				wrap.classList.remove( cls );
			}
		} );

		if ( value ) {
			wrap.classList.add( String( value ) );
		}
	} );
} );


// BOOKING_FORM_LAYOUT_WIDTH — Form width: applies combined "100%" / "600px" / "40rem" to the booking form containers.
WPBC_BFB_Settings_Effects.register( 'booking_form_layout_width', function (value, ctx) {
	const root = ctx && ctx.canvas;
	if ( ! root || ! root.querySelectorAll ) {
		return;
	}

	const wraps = root.querySelectorAll( '.wpbc_bfb__form_preview_section_container' );
	if ( ! wraps.length ) {
		return;
	}

	const v = String( value == null ? '' : value ).trim();

	// allow only "number + unit".
	if ( v && ! /^-?\d+(?:\.\d+)?(?:%|px|rem|em|vw|vh)$/.test( v ) ) {
		return;
	}

	wraps.forEach(
		function (wrap) {
			if ( ! wrap || ! wrap.style ) {
				return;
			}

			if ( ! v ) {
				wrap.style.removeProperty( '--wpbc-bfb-booking_form_layout_width' );
			} else {
				wrap.style.setProperty( '--wpbc-bfb-booking_form_layout_width', v );
			}
		}
	);
} );


// Debug Preview Mode.
WPBC_BFB_Settings_Effects.register( 'booking_bfb_preview_mode', function (value, ctx) {
	const root = ctx.canvas;
	if ( ! root || ! root.querySelectorAll ) {
		return;
	}

	const wraps = root.querySelectorAll( '.wpbc_container.wpbc_form' );
	if ( ! wraps.length ) {
		return;
	}

	// Get builder async.
	wpbc_bfb_api.with_builder(
		function (Builder) {

			/**
			 * Capture active right sidebar tab and return restore handle.
			 *
			 * @return {{restore:function():void}|null}
			 */
			function capture_right_sidebar_active_tab_restore_handle() {

				var tablist_el = document.querySelector( '.wpbc_bfb__rightbar_tabs[role="tablist"]' );
				if ( ! tablist_el ) {
					return null;
				}

				var active_tab_el = tablist_el.querySelector( '[role="tab"][aria-selected="true"]' );

				if ( ! active_tab_el ) {
					active_tab_el = tablist_el.querySelector( '[role="tab"][aria-controls="wpbc_bfb__palette_add_new"]' );
				}

				if ( ! active_tab_el || typeof active_tab_el.click !== 'function' ) {
					return null;
				}

				return {
					restore: function () {
						try { active_tab_el.click(); } catch ( _e ) {}
					}
				};
			}

			var tab_restore_handle = capture_right_sidebar_active_tab_restore_handle();

			let restored  = false;
			var EVS      = window.WPBC_BFB_Core && window.WPBC_BFB_Core.WPBC_BFB_Events ? window.WPBC_BFB_Core.WPBC_BFB_Events : {};
			var EV_DONE  = EVS.STRUCTURE_LOADED || EVS.CANVAS_REFRESHED || 'wpbc:bfb:structure-loaded';


			function do_restore() {
				if ( restored ) { return; }
				restored = true;
				try { Builder?.bus?.off?.( EV_DONE, do_restore ); } catch ( _ ) {}
				requestAnimationFrame( function () {
					if ( ! tab_restore_handle ) { return; }
					tab_restore_handle.restore();
				} );
			}

			// Listen once (best), plus a fallback in case event isn't fired.
			try { Builder?.bus?.on?.( EV_DONE, do_restore ); } catch ( _ ) {}


			var enabled = ('On' === value);
			Builder.set_preview_mode( enabled, { rebuild: true, reinit: true, source: 'settings-effects' } );
		}
	);

} );
