jQuery( function( $ ) {

	$( '.wcpdf-extensions .more' ).hide();

	$( '.wcpdf-extensions > li' ).on( 'click', function( event ) {
		$( this ).toggleClass( 'expanded' );
		$( this ).find( '.more' ).slideToggle();
	} );

	$( '.edit-next-number' ).on( 'click', function( event ) {
		// enable input & show save button
		$( this ).hide();
		$( this ).siblings( 'input' ).prop( 'disabled', false );
		$( this ).siblings( '.save-next-number.button' ).show();
	} );

	$( '.save-next-number' ).on( 'click', function( event ) {
		$input = $( this ).siblings( 'input' );
		$input.addClass( 'ajax-waiting' );
		let number = $input.val();

		if ( number.length > 0 && number > 2147483647 ) {
			alert( wpo_wcpdf_admin.mysql_int_size_limit );
			$input.removeClass( 'ajax-waiting' );
			return;
		}


		let data = {
			security: $input.data( 'nonce' ),
			action:   'wpo_wcpdf_set_next_number',
			store:    $input.data( 'store' ),
			number:   number,
		};

		xhr = $.ajax( {
			type: 'POST',
			url:  wpo_wcpdf_admin.ajaxurl,
			data: data,
			success: function( response ) {
				$input.removeClass( 'ajax-waiting' );
				$input.siblings( '.edit-next-number' ).show();
				$input.prop( 'disabled', 'disabled' );
				$input.siblings( '.save-next-number.button' ).hide();
			}
		} );
	} );

	$( "[name='wpo_wcpdf_documents_settings_invoice[display_number]']" ).on( 'change', function( event ) {
		if ( $( this ).val() == 'order_number' ) {
			$( this ).closest( 'td' ).find( '.description' ).slideDown();
			$( this ).closest( 'tr' ).nextAll( 'tr' ).has( 'input#next_invoice_number' ).first().hide();
		} else {
			$( this ).closest( 'td' ).find( '.description' ).hide();
			$( this ).closest( 'tr' ).nextAll( 'tr' ).has( 'input#next_invoice_number' ).first().show();
		}
	} ).trigger( 'change' );

	// enable settings document switch
	$( '.wcpdf_document_settings_sections > h2' ).on( 'click', function() {
		$( this ).parent().find( 'ul' ).toggleClass( 'active' );
	} );

	// Add admin pointers
	$.each( wpo_wcpdf_admin.pointers, function( key, pointer ) {

		$( pointer.target ).pointer(
			{
				content: pointer.content,

				position:
					{
						edge:  pointer.position.edge,
						align: pointer.position.align
					},

				pointerClass: pointer.pointer_class,

				pointerWidth: pointer.pointer_width,

				close: function() {
					jQuery.post(
						wpo_wcpdf_admin.ajaxurl,
						{
							pointer: key,
							action:  'dismiss-wp-pointer',
						}
					);
				},
			}
		);

		// Check if pointer was dismissed
		if ( $.inArray( key, wpo_wcpdf_admin.dismissed_pointers.split(',') ) === -1 ) {
			$( pointer.target ).pointer('open');
		}

	});

	// enable WooCommerce help tips
	$( '.woocommerce-help-tip' ).tipTip( {
		'attribute': 'data-tip',
		'fadeIn':    50,
		'fadeOut':   50,
		'delay':     200
	} );

	$( '#wpo-wcpdf-preview-wrapper #due_date' ).on( 'change', function() {
		const $due_date_checkbox   = $( '#wpo-wcpdf-preview-wrapper #due_date' );
		const $due_date_days_input = $( '#wpo-wcpdf-preview-wrapper #due_date_days' );

		if ( $due_date_checkbox.is( ':checked' ) ) {
			$due_date_days_input.prop( 'disabled', false );
		} else {
			$due_date_days_input.prop( 'disabled', true );
		}
	} ).trigger( 'change' );

	//----------> Preview <----------//
	// objects
	let $previewWrapper           = $( '#wpo-wcpdf-preview-wrapper' );
	let $preview                  = $( '#wpo-wcpdf-preview-wrapper .preview' );
	let $previewOrderIdInput      = $( '#wpo-wcpdf-preview-wrapper input[name="order_id"]' );
	let $previewDocumentTypeInput = $( '#wpo-wcpdf-preview-wrapper input[name="document_type"]' );
	let $previewOutputFormatInput = $( '#wpo-wcpdf-preview-wrapper input[name="output_format"]' );
	let $previewNonceInput        = $( '#wpo-wcpdf-preview-wrapper input[name="nonce"]' );
	let $previewSettingsForm      = $( '#wpo-wcpdf-settings' );
	let previewXhr                = null;
	let previewSearchXhr          = null;

	// variables
	let previewOrderId, previewDocumentType, previewOutputFormat, previewNonce, previewSettingsFormData, previewTimeout, previewSearchTimeout, previousWindowWidth;

	function loadPreviewData() {
		previewOrderId          = $previewOrderIdInput.val();
		previewDocumentType     = $previewDocumentTypeInput.val();
		previewOutputFormat     = $previewOutputFormatInput.val();
		previewNonce            = $previewNonceInput.val();
		previewSettingsFormData = $previewSettingsForm.serialize();
	}

	function resetDocumentType() {
		$previewDocumentTypeInput.val( $previewDocumentTypeInput.data( 'default' ) ).trigger( 'change' );
	}

	function resetOrderId() {
		$previewOrderIdInput.val( '' ).trigger( 'change' );
	}

	function getPreviewOrderIdFromUrl() {
		const params = new URLSearchParams( window.location.search );
		return params.get( 'preview_order' ) || '';
	}

	function setPreviewOrderIdInUrl( orderId ) {
		function updateParams( params ) {
			if ( orderId ) {
				params.set( 'preview_order', orderId );
			} else {
				params.delete( 'preview_order' );
			}
			return params;
		}

		const params = updateParams( new URLSearchParams( window.location.search ) );
		history.replaceState( null, '', '?' + params.toString() );

		// Update document section links so they carry the param on navigation
		$( '.wcpdf_document_settings_sections a, .doc-output-toggle-group .doc-output-toggle' ).each( function() {
			const href       = $( this ).attr( 'href' );
			const [ path ]   = href.split( '?' );
			const linkParams = updateParams( new URLSearchParams( href.split( '?' )[1] ) );
			$( this ).attr( 'href', path + '?' + linkParams.toString() );
		} );
	}

	resetDocumentType();      // force document type reset

	let urlOrderId = parseInt( getPreviewOrderIdFromUrl(), 10 ) || '';
	if ( urlOrderId ) {
		$previewOrderIdInput.val( urlOrderId );
		$( '.preview-document .order-search-label' ).text( '#' + urlOrderId );
		$( '.preview-document p.last-order' ).hide();
		$( '.preview-document p.order-search' ).show();
	} else {
		resetOrderId();       // force order ID reset
	}

	loadPreviewData();        // load preview data

	previousWindowWidth = $( window ).width();
	determinePreviewStates(); // determine preview states based on screen size

	$( window ).on( 'resize', determinePreviewStates );

	function determinePreviewStates() {
		// Check if preview states are allowed to change based on screen size
		if ( $previewWrapper.attr( 'data-preview-states-lock') == false ) {

			// On small screens: 2 preview states and close preview
			if ( $(this).width() <= 1200 && ( previousWindowWidth > 1200 || $(this).width() == previousWindowWidth ) ) {
				if ( $previewWrapper.attr( 'data-preview-state') == 'full' ) {
					$previewWrapper.find( '.preview-document' ).show();
					$previewWrapper.find( '.sidebar' ).hide();
					$previewWrapper.find( '.slide-left' ).hide();
					$previewWrapper.find( '.slide-right' ).show();
					$previewWrapper.attr( 'data-preview-states', 2 );
					$previewWrapper.attr( 'data-preview-state', 'full' );
					$previewWrapper.attr( 'data-from-preview-state', '' );
				} else {
					$previewWrapper.find( '.preview-document' ).hide();
					$previewWrapper.find( '.sidebar' ).show();
					$previewWrapper.find( '.slide-left' ).show();
					$previewWrapper.find( '.slide-right' ).hide();
					$previewWrapper.attr( 'data-preview-states', 2 );
					$previewWrapper.attr( 'data-preview-state', 'closed' );
					$previewWrapper.attr( 'data-from-preview-state', '' );
				}

			// On larger screens: 3 preview states and show settings as sidebar
			} else if ( $(this).width() > 1200 && ( previousWindowWidth <= 1200 || $(this).width() == previousWindowWidth ) ) {
				if ( $previewWrapper.attr( 'data-preview-state') == 'full' ) {
					$previewWrapper.find( '.preview-document' ).show();
					$previewWrapper.find( '.sidebar' ).hide();
					$previewWrapper.find( '.slide-left' ).hide();
					$previewWrapper.find( '.slide-right' ).show();
					$previewWrapper.attr( 'data-preview-states', 3 );
					$previewWrapper.attr( 'data-preview-state', 'full' );
					$previewWrapper.attr( 'data-from-preview-state', 'sidebar' );
					$previewWrapper.addClass( 'static' );
				} else if ( $previewWrapper.attr( 'data-preview-state') == 'closed' && $(this).width() !== previousWindowWidth ) {
					$previewWrapper.find( '.preview-document' ).hide();
					$previewWrapper.find( '.sidebar' ).show();
					$previewWrapper.find( '.slide-left' ).show();
					$previewWrapper.find( '.slide-right' ).hide();
					$previewWrapper.attr( 'data-preview-states', 3 );
					$previewWrapper.attr( 'data-preview-state', 'closed' );
					$previewWrapper.attr( 'data-from-preview-state', '' );
					$previewWrapper.removeClass( 'static' );
				} else {
					$previewWrapper.find( '.preview-document, .sidebar' ).show();
					$previewWrapper.find( '.slide-left, .slide-right' ).show();
					$previewWrapper.attr( 'data-preview-states', 3 );
					$previewWrapper.attr( 'data-preview-state', 'sidebar' );
					$previewWrapper.attr( 'data-from-preview-state', '' );
					$previewWrapper.removeClass( 'static' );
				}
			}
		}
		previousWindowWidth = $(this).width();
	}

	$( '.slide-left' ).on( 'click', function() {
		let previewStates = $previewWrapper.attr( 'data-preview-states' );
		let previewState  = $previewWrapper.attr( 'data-preview-state' );

		$previewWrapper.find( '.preview-data-wrapper ul' ).removeClass( 'active' );

		if ( previewStates == 3 ) {
			if ( previewState == 'closed' ) {
				$previewWrapper.find( '.preview-document' ).show();
				$previewWrapper.find( '.slide-right' ).show();
				$previewWrapper.attr( 'data-preview-state', 'sidebar' );
				$previewWrapper.attr( 'data-from-preview-state', 'closed' );
			} else {
				$previewWrapper.find( '.slide-left' ).hide();
				$previewWrapper.find( '.sidebar' ).delay(300).hide(0);
				$previewWrapper.attr( 'data-preview-state', 'full' );
				$previewWrapper.attr( 'data-from-preview-state', 'sidebar' );
				makePreviewScrollable( $previewWrapper );
			}
		} else {
			$previewWrapper.find( '.preview-document' ).show();
			$previewWrapper.find( '.slide-left' ).hide();
			$previewWrapper.find( '.slide-right' ).show();
			$previewWrapper.attr( 'data-preview-state', 'full' );
			$previewWrapper.attr( 'data-from-preview-state', 'closed' );
			makePreviewScrollable( $previewWrapper );
		}
	} );

	$( '.slide-right' ).on( 'click', function() {
		let previewStates = $previewWrapper.attr( 'data-preview-states' );
		let previewState  = $previewWrapper.attr( 'data-preview-state' );

		$previewWrapper.find( '.preview-data-wrapper ul' ).removeClass( 'active' );

		if ( previewStates == 3 ) {
			if ( previewState == 'full' ) {
				$previewWrapper.find( '.slide-left' ).delay(400).show(0);
				$previewWrapper.find( '.sidebar' ).show();
				$previewWrapper.attr( 'data-preview-state', 'sidebar' );
				$previewWrapper.attr( 'data-from-preview-state', 'full' );
			} else {
				$previewWrapper.find( '.preview-document' ).hide(300);
				$previewWrapper.find( '.slide-right' ).hide();
				$previewWrapper.attr( 'data-preview-state', 'closed' );
				$previewWrapper.attr( 'data-from-preview-state', 'sidebar' );
			}
		} else {
			$previewWrapper.find( '.preview-document' ).hide(300);
			$previewWrapper.find( '.slide-left' ).show();
			$previewWrapper.find( '.slide-right' ).hide();
			$previewWrapper.attr( 'data-preview-state', 'closed' );
			$previewWrapper.attr( 'data-from-preview-state', 'full' );
		}
		$previewWrapper.removeClass( 'static' );
	} );

	function makePreviewScrollable( wrapper ) {
		window.scrollTo( 0, 0 );
		let $wrapper = wrapper;
		// Make preview scrollable after panel animation is complete
		setTimeout( function() {
			$wrapper.addClass( 'static' );
		}, 300 );
	}

	$( '.preview-document .preview-data p' ).on( 'click', function() {
		let $previewData = $( this ).closest( '.preview-data' );
		$previewData.siblings( '.preview-data' ).find( 'ul' ).removeClass( 'active' );
		$previewData.find( 'ul' ).toggleClass( 'active' );
	} );

	$( '.preview-document .preview-order-data ul > li' ).on( 'click', function() {
		let $previewData = $( this ).closest( '.preview-data' );
		$previewData.find( 'ul' ).toggleClass( 'active' );
		if ( $( this ).hasClass( 'order-search' ) ) {
			$previewData.find( 'p.last-order' ).hide();
			$previewData.find( 'input[name="preview-order-search"]' ).addClass( 'active' );
			$previewData.find( 'p.order-search' ).show().find( '.order-search-label' ).text( $( this ).text() );
		} else {
			$previewData.find( 'p.last-order' ).show();
			$previewData.find( 'p.order-search' ).hide();
			$previewData.find( 'input[name="preview-order-search"]' ).removeClass( 'active' ).val( '' );
			$previewData.find( '#preview-order-search-results' ).hide();
			$previewData.find( 'img.preview-order-search-clear' ).hide(); // remove the clear button
			setPreviewOrderIdInUrl( '' );
			resetOrderId()    // force order ID reset
			triggerPreview(); // trigger preview
		}
	} );

	// Preview on page load
	triggerPreview();

	// Custom trigger to signify settings have changed (will show save button and refresh preview)
	$( document ).on( 'wpo-wcpdf-settings-changed', function( event, delay ) {
		showSaveBtn();
		triggerPreview( delay );
	} );

	// Custom trigger to refresh preview
	$( document ).on( 'wpo-wcpdf-refresh-preview wpo_wcpdf_refresh_preview', function( event, delay ) {
		triggerPreview( delay );
	} );

	// Preview on user click in search result
	$( document ).on( 'click', '#preview-order-search-results a', function( event ) {
		event.preventDefault();
		let selectedOrderId = $( this ).data( 'order_id' );
		setPreviewOrderIdInUrl( selectedOrderId );
		$( '.preview-document .order-search-label' ).text( '#' + selectedOrderId );
		$previewOrderIdInput.val( selectedOrderId ).trigger( 'change' );
		$( this ).closest( 'div' ).hide();                   // hide results div
		$( this ).closest( 'div' ).children( 'a' ).remove(); // remove all results
		triggerPreview();
	} );

	// Check for settings change
	$( document ).on( 'keyup paste', '#wpo-wcpdf-settings input, #wpo-wcpdf-settings textarea', settingsChanged );
	$( document ).on( 'change', '#wpo-wcpdf-settings input[type="checkbox"], #wpo-wcpdf-settings input[type="radio"], #wpo-wcpdf-settings select', function( event ) {
		if ( 'shop_address_country' === event.target.id || ! event.isTrigger ) { // exclude programmatic triggers that aren't actually changing anything
			settingsChanged( event );
		}
	} );
	$( document ).on( 'select2:select select2:unselect', '#wpo-wcpdf-settings select.wc-enhanced-select', settingsChanged );
	$( document.body ).on( 'wpo-wcpdf-media-upload-setting-updated', settingsChanged );
	$( document ).on( 'click', '.wpo_remove_image_button, #wpo-wcpdf-settings .remove-requirement', settingsChanged );

	// On Multilingual
	if ( $( '#wpo_wcpdf_settings_general-shop_address_country-translations' ).length > 0 ) {
		$( '#wpo-wcpdf-settings select[name^="wpo_wcpdf_settings_general[shop_address_country]"]' ).each( function() {
			const $select = $( this );
			if ( $select.val() ) {
				shopCountryChanged( $select );
			}
		} );
	}

	function settingsChanged( event, previewDelay ) {
		if ( 'shop_address_country' === event.target.id ) {
			shopCountryChanged( $( event.target ) );
		}

		// Show secondary save button
		showSaveBtn();

		// Check if preview needs to reload and with what delay
		let $element = $( event.target );

		if ( ! settingIsExcludedForPreview( $element.attr('name') ) ) {

			if ( $element.hasClass( 'remove-requirement' ) || $element.attr('id') == 'disable_for' ) {
				return;
			}

			if ( $.inArray( event.type, ['keyup', 'paste'] ) !== -1 ) {
				if ( $element.is( 'input[type="checkbox"], select' ) ) {
					return;
				} else {
					previewDelay = event.type == 'keyup' ? 1000 : 0;
				}
			}

			triggerPreview( previewDelay );
		}
	}

	function shopCountryChanged( $countryField ) {
		const selectedCountry = $countryField.val();
		const $form           = $countryField.closest( 'form' );

		// Get the language key
		const nameMatch = $countryField.attr( 'name' )
			.match( /\[shop_address_country]\[(.*?)\]/ ); // 'pt-pt', 'default', etc.
		const lang      = nameMatch ? nameMatch[1] : 'default';

		// Find the matching state field for that language
		const $state = $form.find( `select[name="wpo_wcpdf_settings_general[shop_address_state][${lang}]"]` );

		// Keep the original button lookup, but relative to $state
		const $state_sync_button = $state
			.closest( '.wpo-wcpdf-input-wrapper' )
			.find( '#shop_address_state_action' );

		// Clear previous states
		$state.empty().prop( 'disabled', true );
		$state_sync_button.prop( 'disabled', true );

		// Temporary loading option
		$state.append(
			$( '<option>', {
				value: '',
				text: wpo_wcpdf_admin.shop_country_changed_messages.loading
			} )
		);

		return $.ajax( {
			url:      wpo_wcpdf_admin.ajaxurl,
			type:     'POST',
			dataType: 'json',
			data: {
				action: 'wcpdf_get_country_states',
				country: selectedCountry,
				security: wpo_wcpdf_admin.nonce,
			},
			success: function( response ) {
				$state.empty();

				const states   = response.data?.states;
				const selected = response.data?.selected;

				if ( response.success && states && Object.keys( states ).length > 0 ) {
					$.each( states, function( code, name ) {
						$state.append(
							$( '<option>', {
								value: code,
								text: name,
								selected: code === selected
							} )
						);
					} );
					$state.prop( 'disabled', false );
					$state_sync_button.prop( 'disabled', false );
				} else {
					$state.append(
						$( '<option>', {
							value: '',
							text: wpo_wcpdf_admin.shop_country_changed_messages.empty
						} )
					);
				}

				triggerPreview();
			},
			error: function() {
				$state.empty().append(
					$( '<option>', {
						value: '',
						text: wpo_wcpdf_admin.shop_country_changed_messages.error
					} )
				);

				triggerPreview();
			}
		} );
	}

	function showSaveBtn( event ) {
		$( '.preview-data-wrapper .save-settings p' ).css( 'margin-right', '0' );
	}

	// Submit settings form when clicking on secondary save button
	$( document.body ).on( 'click', '.preview-data-wrapper .save-settings p input', function( event ) {
		$( '#wpo-wcpdf-settings input#submit' ).trigger( 'click' );
	} );

	// Trigger the Preview
	function triggerPreview( timeoutDuration = 0 ) {
		$previewStates = $( '#wpo-wcpdf-preview-wrapper' ).data( 'preview-states' );

		// Check if preview is disabled and return
		if ( 'undefined' === $previewStates || 1 === $previewStates ) {
			return;
		}

		timeoutDuration = typeof timeoutDuration == 'number' ? timeoutDuration : 0;

		loadPreviewData();
		clearTimeout( previewTimeout );
		previewTimeout = setTimeout( function() { ajaxLoadPreview() }, timeoutDuration );
	}

	// Settings excluded from trigger the Preview
	function settingIsExcludedForPreview( settingName ) {
		let excluded = false;
		if ( ! settingName ) {
			return excluded;
		}
		let nameKey = settingName.includes( '[' ) ? settingName.match(/\[(.*?)\]/)[1] : settingName;
		if ( $.inArray( nameKey, wpo_wcpdf_admin.preview_excluded_settings ) !== -1 ) {
			excluded = true;
		}
		return excluded;
	}

	// Clear preview order search results/input
	$( document ).on( 'click', 'img.preview-order-search-clear', function( event ) {
		event.preventDefault();
		$( this ).closest( 'div' ).find( 'input#preview-order-search' ).val( '' );
		$( this ).closest( '.preview-data' ).find( '#preview-order-search-results' ).children( 'a' ).remove();      // remove previous results
		$( this ).closest( '.preview-data' ).find( '#preview-order-search-results' ).children( '.error' ).remove(); // remove previous errors
		$( this ).closest( '.preview-data' ).find( '#preview-order-search-results' ).hide();
		$( this ).hide();
	} );

	// Trigger preview on document selection and change the document type input with the new value
	$( '#wpo-wcpdf-preview-wrapper ul.preview-data-option-list li' ).on( 'click', function() {
		let inputName = $( this ).closest( 'ul' ).data( 'input-name' );
		let $input    = $( '#wpo-wcpdf-preview-wrapper :input[name='+inputName+']');
		$input.val( $( this ).data( 'value' ) ).trigger( 'change' );
	} );

	// Detect document type input changes and apply the same document title to the document selector
	$previewDocumentTypeInput.on( 'change', function() {
		let inputValue = $( this ).val();
		if ( inputValue.length ) {
			let inputName   = $( this ).attr( 'name' );
			let $ul         = $( '#wpo-wcpdf-preview-wrapper ul.preview-data-option-list[data-input-name='+inputName+']' );
			let $li         = $ul.find( 'li[data-value='+inputValue+']' );
			let xmlDocTypes = wpo_wcpdf_admin.xml_document_types || [];
			let supportsXml = xmlDocTypes.indexOf( inputValue ) !== -1;
			let $xmlToggle  = $( '.doc-output-toggle-group .doc-output-toggle' ).filter( function() {
				return $( this ).text().trim().toLowerCase() === 'xml';
			} );

			$ul.parent().find( '.current-label' ).text( $li.text() );

			// show/hide XML toggle based on whether the document type supports it
			$xmlToggle.toggle( supportsXml );

			// if XML is not supported and the current format is XML, fall back to PDF
			if ( ! supportsXml && $previewOutputFormatInput.val() === 'xml' ) {
				$previewOutputFormatInput.val( 'pdf' );

				$preview.empty();

				const formatParams = new URLSearchParams( window.location.search );
				formatParams.delete( 'output_format' );
				history.replaceState( null, '', '?' + formatParams.toString() );

				$( '.doc-output-toggle-group .doc-output-toggle' ).removeClass( 'active' ).filter( function() {
					return $( this ).text().trim().toLowerCase() === 'pdf';
				} ).addClass( 'active' );
			}

			triggerPreview();
		}
	} ).trigger( 'change' );

	// Detect order ID input changes
	$previewOrderIdInput.on( 'change', function() {
		triggerPreview();
	} ).trigger( 'change' );

	// Load the Preview with AJAX
	function ajaxLoadPreview() {
		console.log( 'Loading preview...' );
		let worker   = wpo_wcpdf_admin.pdfjs_worker;
		let canvasId = 'preview-canvas';
		let data     = {
			action:        'wpo_wcpdf_preview',
			security:      previewNonce,
			order_id:      previewOrderId,
			document_type: previewDocumentType,
			output_format: previewOutputFormat,
			data:          previewSettingsFormData,
		};

		// remove previous error notices
		$preview.children( '.notice' ).remove();

		// block ui
		$preview.block( {
			message: null,
			overlayCSS: {
				background: '#fff',
				opacity: 0.6
			}
		} );

		previewXhr = $.ajax( {
			type:    'POST',
			url:     wpo_wcpdf_admin.ajaxurl,
			data:    data,
			beforeSend: function( jqXHR, settings ) {
				if ( previewXhr != null ) {
					previewXhr.abort();
				}
			},
			success: function( response, textStatus, jqXHR ) {
				if ( response.data.error ) {
					$( '#' + canvasId ).remove();
					$preview.append( '<div class="notice notice-warning inline"><p>' + response.data.error + '</p></div>' );
				} else if ( response.data.preview_data && response.data.output_format ) {
					$( '#' + canvasId ).remove();

					switch ( response.data.output_format ) {
						default:
						case 'pdf':
							$preview.append( '<canvas id="' + canvasId + '" style="width:100%;"></canvas>' );
							renderPdf( worker, canvasId, response.data.preview_data );
							break;
						case 'xml': {
							const rawXml = response.data.preview_data;

							// pretty-print xmlns declarations:
							const pretty = rawXml.replace( /\s+(xmlns(?::[\w.-]+)?=)/g, '\n $1' );

							// build <pre><code> safely
							const $code = $( '<code>', { class: 'language-xml' } ).text( pretty );
							$preview.empty().append( $( '<pre>' ).append( $code ) );

							// highlight just this element
							Prism.highlightElement( $code[0] );
							break;
						}
					}
				}

				$preview.unblock();
			},
			error: function( jqXHR, textStatus, errorThrown ) {
				if ( textStatus != 'abort' ) {
					let errorMessage = jqXHR.status + ': ' + jqXHR.statusText
					$( '#' + canvasId ).remove();
					$preview.append( '<div class="notice notice-warning inline"><p>' + errorMessage + '</p></div>' );
					$preview.unblock();
				}
			},
		} );
	}

	// pdf_js (third party library code)
	function renderPdf( worker, canvasId, pdfData ) {
		// atob() is used to convert base64 encoded PDF to binary-like data.
		// (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding.)
		pdfData = window.atob( pdfData );

		// The workerSrc property shall be specified.
		pdfjsLib.GlobalWorkerOptions.workerSrc = worker;

		// Using DocumentInitParameters object to load binary data.
		let loadingTask = pdfjsLib.getDocument( { data: pdfData } );
		loadingTask.promise.then( function( pdf ) {
			// Fetch the first page
			let pageNumber = 1;
			pdf.getPage( pageNumber ).then( function( page ) {
				let scale     = 2;
				let viewport  = page.getViewport( { scale: scale } );

				// Prepare canvas using PDF page dimensions
				let canvas    = document.getElementById( canvasId );
				let context   = canvas.getContext( '2d' );

				canvas.height = viewport.height;
				canvas.width  = viewport.width;

				// Render PDF page into canvas context
				let renderContext = {
					canvasContext: context,
					viewport:      viewport
				};
				let renderTask = page.render( renderContext );
				renderTask.promise.then( function() {
					// page rendered
				} );
			} );
		}, function( reason ) {
			// PDF loading error
			console.error( reason );
		} );
	}

	// Preview on user input
	$( '#preview-order-search' ).on( 'keyup paste', function( event ) {
		let $elem = $( this );
		$elem.addClass( 'ajax-waiting' );
		let duration = event.type == 'keyup' ? 1000 : 0;
		loadPreviewData();
		clearTimeout( previewSearchTimeout );
		previewSearchTimeout = setTimeout( function() { previewOrderSearch( $elem ) }, duration );
	} );

	// Preview order search
	function previewOrderSearch( $elem ) {
		let $div   = $elem.closest( '.preview-data' ).find( '#preview-order-search-results' );
		let value  = $elem.val();
		let nonce  = $elem.data( 'nonce' );
		let action = 'wpo_wcpdf_preview_order_search';

		let data = {
			security:      nonce,
			action:        action,
			search:        value,
			document_type: previewDocumentType,
		};

		$div.parent().find( 'img.preview-order-search-clear' ).hide(); // hide the clear button
		$div.children( '.error' ).remove();                            // remove previous errors
		$div.children( 'a' ).remove();                                 // remove previous results
		$div.hide();

		previewSearchXhr = $.ajax( {
			type: 'POST',
			url:  wpo_wcpdf_admin.ajaxurl,
			data: data,
			beforeSend: function( jqXHR, settings ) {
				if ( previewSearchXhr != null ) {
					previewSearchXhr.abort();
				}
			},
			success: function( response ) {
				if ( response.data ) {
					if ( response.data.error ) {
						$div.append( '<span class="error">'+response.data.error+'</span>' );
						$div.show();
					} else {
						$.each( response.data, function( i, item ) {
							let firstLine = '<a data-order_id="'+i+'"><span class="order-number">#'+item.order_number+'</span> - '+item.billing_first_name+' '+item.billing_last_name;
							if ( item.billing_company.length > 0 ) {
								firstLine = firstLine+', '+item.billing_company;
							}
							let secondLine = '<br><span class="date">'+item.date_created+'</span><span class="total">'+item.total+'</span></a>';
							$div.append( firstLine+secondLine );
							$div.show();
						} );
					}
				}

				$elem.removeClass( 'ajax-waiting' );
				$elem.closest( 'div' ).find( 'img.preview-order-search-clear' ).show();
			},
			error: function( jqXHR, textStatus ) {
				if ( textStatus !== 'abort' ) {
					$div.append( '<span class="error">' + jqXHR.status + ': ' + jqXHR.statusText + '</span>' );
					$div.show();
					$elem.removeClass( 'ajax-waiting' );
				}
			},
		} );
	}

	//----------> /Preview <----------//
	//----------> Settings Accordion <----------//

	function settingsAccordion() {
		// Get current tab.
		const params      = new URLSearchParams( window.location.search );
		const allowedTabs = [ 'general', 'documents', 'debug' ];
		const tab         = params.get( 'tab' ) || 'general';

		if ( ! allowedTabs.includes( tab ) ) {
			return;
		}

		const tabsMainCategory = {
			general   : 'display',
			documents : 'general',
			debug     : 'filesystem_access' // Default open section for Advanced/Debug tab
		};

		const sections = $( '.settings_category h2' );

		if ( sections.length === 0 ) {
			return; // No sections found
		}

		// Accessibility attributes for accordion headers and panels
		sections.each( function ( index ) {
			const $header   = $( this );
			const $panel    = $header.next( '.form-table' );
			const $category = $header.parent( '.settings_category' );
			const idBase    = $category.attr( 'id' ) || $header.attr( 'id' ) || `wcpdf_${tab}_section_${index}`;

			// Ensure header has an id and compute explicit ids
			if ( ! $header.attr( 'id' ) ) {
				$header.attr( 'id', `${idBase}_header` );
			}
			const headerElementId = $header.attr( 'id' );
			const panelId         = `${idBase}_panel`;

			$header.attr( {
				'role': 'button',
				'tabindex': 0,
				'aria-controls': panelId
			} );

			$panel.attr( {
				'id': panelId,
				'role': 'region',
				'aria-labelledby': headerElementId
			} );
		} );

		// Initialize accordion state
		sections.each( function ( index ) {
			const $header    = $( this );
			const $category  = $header.parent( '.settings_category' );
			const categoryId = $category.attr( 'id' ) || `wcpdf_${tab}_section_${index}`;
			const $panel     = $header.next( '.form-table' );

			// Check localStorage for saved state
			const stored = localStorage.getItem( `wcpdf_${tab}_settings_accordion_state_${categoryId}` );
			let shouldOpen = false;

			if ( stored !== null ) {
				// User has previously interacted with this section - use saved state
				shouldOpen = stored === 'true';
			} else if ( tabsMainCategory[ tab ] && categoryId === tabsMainCategory[ tab ] ) {
				// First visit - open the default main category for this tab
				shouldOpen = true;
			}
			// else: keep collapsed (shouldOpen = false)

			// Set initial state
			if ( shouldOpen ) {
				$header.addClass( 'active' ).attr( 'aria-expanded', true );
				$panel.show().attr( 'aria-hidden', 'false' );
			} else {
				$header.removeClass( 'active' ).attr( 'aria-expanded', false );
				$panel.hide().attr( 'aria-hidden', 'true' );
			}
		} );

		// Toggle section on click
		function toggleSection( header ) {
			const $header    = $( header );
			const categoryId = $header.parent( '.settings_category' ).attr( 'id' );
			const $panel     = $header.next( '.form-table' );
			const willOpen   = ! $panel.is( ':visible' );

			$header.toggleClass( 'active', willOpen ).attr( 'aria-expanded', willOpen );

			$panel.stop( true, false ).slideToggle( {
				duration: 300,
				easing: 'swing',
				complete: function () {
					const isVisible = $( this ).is( ':visible' );
					$( this ).attr( 'aria-hidden', isVisible ? 'false' : 'true' );
					if ( categoryId ) {
						localStorage.setItem( `wcpdf_${tab}_settings_accordion_state_${categoryId}`, isVisible );
					}
				}
			} );
		}

		// Bind click events
		sections.off( 'click' ).on( 'click', function () {
			toggleSection( this );
		} );

		// Keyboard accessibility
		sections.off( 'keydown' ).on( 'keydown', function ( e ) {
			if ( e.key === 'Enter' || e.key === ' ' ) {
				e.preventDefault();
				toggleSection( this );
			}
		} );
	}

	// Initialize accordion
	settingsAccordion();
	//----------> /Settings Accordion <----------//

	//----------> Settings Search <----------//

	function settingsSearch() {
		const $input = $( '#wpo-settings-search' );

		if ( ! $input.length ) {
			return;
		}

		// Check if search index is available.
		if ( ! wpo_wcpdf_admin.search_index.length ) {
			return;
		}

		const $searchContainer = $input.closest( '.settings-search' );

		// Create dropdown container.
		$searchContainer.find( '.settings-search-dropdown' ).remove();
		const $dropdown = $( '<ul class="settings-search-dropdown"></ul>' );
		$searchContainer.append( $dropdown );

		let activeIndex = -1;
		let matches     = [];

		function findSettingRow( item ) {
			const $category = $( '#' + item.category );

			if ( ! $category.length ) {
				return $();
			}

			return $category.find( '[name*="[' + item.id + ']"]' ).first().closest( 'tr' );
		}

		function renderResults( query ) {
			$dropdown.empty();
			activeIndex = -1;
			matches     = [];

			if ( ! query ) {
				$dropdown.hide();
				return;
			}

			matches = wpo_wcpdf_admin.search_index.filter( function ( item ) {
				return item.label.toLowerCase().indexOf( query.toLowerCase().trim() ) !== -1;
			} );

			if ( ! matches.length ) {
				$dropdown.hide();
				return;
			}

			$.each( matches, function ( index, item ) {
				const $item = $( '<li class="settings-search-item"></li>' )
					.text( item.label )
					.attr( 'data-index', index )
					.on( 'mousedown', function ( e ) {
						e.preventDefault();
						navigateToSetting( item );
					} );
				$dropdown.append( $item );
			} );

			$dropdown.show();
		}

		function setActiveItem( index ) {
			const $items = $dropdown.find( '.settings-search-item' );

			if ( ! $items.length ) {
				return;
			}

			// Clamp index.
			if ( index < 0 ) {
				index = $items.length - 1;
			} else if ( index >= $items.length ) {
				index = 0;
			}

			activeIndex = index;
			$items.removeClass( 'active' );
			$items.eq( activeIndex ).addClass( 'active' );

			// Scroll into view.
			const el = $items.get( activeIndex );
			if ( el ) {
				el.scrollIntoView( { block: 'nearest' } );
			}
		}

		function navigateToSetting( item ) {
			$dropdown.hide();
			$input.val( '' );

			const $category = $( '#' + item.category );

			// Early return if category is not found.
			if ( ! $category.length ) {
				return;
			}

			// Find the target row by setting ID.
			const $row = findSettingRow( item );

			// Early return if row is not found.
			if ( ! $row.length ) {
				return;
			}

			// Open the category and store the state in the local storage.
			const $header = $category.find( '> h2' );
			const $panel  = $header.next( '.form-table' );

			// Open the accordion section if closed.
			if ( $panel.length && ! $panel.is( ':visible' ) ) {
				$header.addClass( 'active' ).attr( 'aria-expanded', true );
				$panel.show().attr( 'aria-hidden', 'false' );

				const params = new URLSearchParams( window.location.search );
				const tab    = params.get( 'tab' ) || 'general';

				localStorage.setItem( `wcpdf_${tab}_settings_accordion_state_${item.category}`, 'true' );
			}

			// Scroll to and highlight the row.
			const offset = $row.offset().top - 150;
			$( 'html, body' ).animate( { scrollTop: offset }, 300, function () {
				$row.addClass( 'settings-search-highlight' );
				setTimeout( function () {
					$row.removeClass( 'settings-search-highlight' );
				}, 1500 );
			} );
		}

		// Input events.
		$input.on( 'input', function () {
			renderResults( $( this ).val().trim() );
		} );

		$input.on( 'keydown', function ( e ) {
			if ( ! $dropdown.is( ':visible' ) ) {
				return;
			}

			if ( 'ArrowDown' === e.key ) {
				e.preventDefault();
				setActiveItem( activeIndex + 1 );
			} else if ( 'ArrowUp' === e.key ) {
				e.preventDefault();
				setActiveItem( activeIndex - 1 );
			} else if ( 'Enter' === e.key ) {
				e.preventDefault();
				if ( activeIndex >= 0 && matches[ activeIndex ] ) {
					navigateToSetting( matches[ activeIndex ] );
				}
			} else if ( 'Escape' === e.key ) {
				$dropdown.hide();
				$input.val( '' );
			}
		} );

		$( document ).on( 'mousedown', function ( e ) {
			if ( ! $( e.target ).closest( '.settings-search' ).length ) {
				$dropdown.hide();
			}
		} );

		$input.on( 'focus', function () {
			const val = $( this ).val().trim();
			if ( val ) {
				renderResults( val );
			}
		} );
	}

	settingsSearch();
	//----------> /Settings Search <----------//

	//----------> Conditional Visibility <----------//
	const bound = new Set();

	$( '[data-show_for_option_name]' ).each( function () {
		const opt = $( this ).data( 'show_for_option_name' );
		if ( bound.has( opt ) ) {
			return;
		}

		$( document ).on( 'change', `[name="${opt}"], [name="${opt}[]"]`, toggle_conditional_visibility );
		$( `[name="${opt}"], [name="${opt}[]"]` ).each( function () {
			toggle_conditional_visibility( { target: this } );
		} );
		bound.add( opt );
	} );

	function toggle_conditional_visibility( e ) {
		const $this = $( e.target );
		let name    = ( $this.prop( 'name' ) || '' ).replace( /\[\]$/, '' );

		if ( ! name ) {
			return;
		}

		let value    = $this.val();
		let checkbox = false;

		const $controllerRow     = $this.closest( 'tr' );
		const controllerIsVisible = ! $controllerRow.length || $controllerRow.is( ':visible' );

		if ( $this.is( ':checkbox' ) ) {
			value    = $this.is( ':checked' );
			checkbox = true;
		}

		$( "[data-show_for_option_name='" + name + "']" ).each( function() {
			const $conditional = $( this );
			const $row         = $conditional.closest( 'tr' );

			let show       = false;
			let show_for   = $conditional.data( 'show_for_option_values' );
			let keep_value = $conditional.data( 'keep_current_value' );

			if ( ! Array.isArray( show_for ) ) {
				show_for = [ show_for ];
			}

			show_for = show_for.map( String );

			if ( ! controllerIsVisible ) {
				show = false;
			} else if ( checkbox ) {
				show = value;
			} else if ( Array.isArray( value ) ) {
				show = value.some( item => show_for.includes( String( item ) ) );
			} else {
				show = show_for.includes( String( value ) );
			}

			if ( show ) {
				const wasHidden = ! $row.is( ':visible' );

				$row.show();

				if ( checkbox ) {
					$row.find( ':input[type=checkbox]' ).val( '1' );
				}

				// Re-evaluate nested conditionals when this row becomes visible.
				if ( wasHidden ) {
					$row.find( ':input' ).trigger( 'change' );
				}
			} else {
				$row.hide()
					.find( ':input' ).each( function () {
						const $input = $( this );

						// Even when keeping the value, trigger change so child conditionals are hidden too.
						if ( keep_value ) {
							$input.trigger( 'change' );
							return;
						}

						if ( $input.is( 'select' ) ) {
							if ( $input.prop( 'multiple' ) ) {
								$input.val( [] );
							} else {
								$input.prop( 'selectedIndex', 0 );
							}
						} else if ( $input.is( ':checkbox' ) ) {
							$input.prop( 'checked', false );
						} else {
							$input.val( '' );
						}

						$input.trigger( 'change' );
					} );
			}
		} );
	}
	//----------> /Conditional Visibility <----------//

	//----------> Sync Address <----------//

	$( '#wpo-wcpdf-settings .sync-address' ).on( 'click', function( event ) {
		event.preventDefault();

		const $button  = $( this );
		const $form    = $( this ).closest('form');
		const $icon    = $button.find( 'span.dashicons' );
		const $tooltip = $button.closest( '.wpo-wcpdf-input-wrapper' ).find( '.sync-tooltip' );
		let $field     = $button.closest( '.wpo-wcpdf-input-wrapper' ).find( 'input' );

		if ( $field.length === 0 ) {
			$field = $button.closest( '.wpo-wcpdf-input-wrapper' ).find( 'select' );
		}

		// Rotate the icon to indicate processing.
		$icon.toggleClass( 'rotate' );

		$.ajax( {
			type: 'POST',
			url:  wpo_wcpdf_admin.ajaxurl,
			data: {
				action:        'wpo_wcpdf_sync_address',
				security:      wpo_wcpdf_admin.nonce,
				address_field: $field.attr( 'id' ),
			},
			success: function( response ) {
				if ( response.success && response.data.value && '' !== response.data.value.trim() ) {
					if ( 'shop_address_country' === $field.attr( 'id' ) ) {
						const country_state = response.data.value.split( ':' );
						$field.val( country_state[0] );

						// Update states if the country changed.
						shopCountryChanged( $field ).done( function() {
							const matches     = $field.attr( 'name' ).match( /\[([^\]]+)\]/g ); // matches all bracket parts
							const lang        = matches ? matches[ matches.length - 1 ].replace( /[\[\]]/g, '' ) : 'default';
							const $stateField = $form.find( `select[name="wpo_wcpdf_settings_general[shop_address_state][${lang}]"]` );

							// Update the selected state.
							if ( $stateField.length !== 0 ) {
								$stateField.val( country_state[1] );
							}
						} );
					} else {
						$field.val( response.data.value );
					}

					triggerPreview();
				} else if ( ! response.success && response.data.message && '' !== response.data.message.trim() ) {
					$tooltip.text( response.data.message ).addClass( 'visible' );
					setTimeout( function() {
						$tooltip.removeClass( 'visible' );
					}, 3000 );
				}
			},
			complete: function() {
				// Reset the icon rotation.
				$icon.toggleClass( 'rotate' );
			}
		} );

	} );

	//----------> /Sync Address <----------//

} );
