/**
 * MasterQuiz AI - Frontend JavaScript
 *
 * Handles: file upload (drag & drop + click), quiz generation via WP AJAX,
 * job status polling, quiz result display with navigation, export, and
 * LearnDash quiz creation.
 *
 * Depends on `masterquizConfig` localized by MasterQuiz_Shortcode::render().
 *
 * @package MasterQuiz
 * @since   1.0.0
 */

/* global masterquizConfig */

( function () {
	'use strict';

	/* =========================================================
	   Guard – config must be present
	   ========================================================= */
	if ( typeof masterquizConfig === 'undefined' ) {
		return;
	}

	var cfg  = masterquizConfig;
	var i18n = cfg.i18n || {};

	/* =========================================================
	   State
	   ========================================================= */
	var selectedFile      = null;
	var currentJobId      = null;
	var quizData          = null;
	var allQuestions       = [];
	var currentQIndex     = 0;
	var generationRunning = false;
	var pollTimer         = null;
	var fileUploaded      = false;
	var uploadInProgress  = false;
	var uploadPromise     = null;

	/* =========================================================
	   DOM references (resolved once on init)
	   ========================================================= */
	var el = {};

	function resolveElements() {
		el.wrapper       = document.getElementById( 'masterquiz-wrapper' );
		el.dropzone      = document.getElementById( 'masterquiz-dropzone' );
		el.dropContent   = document.getElementById( 'masterquiz-dropzone-content' );
		el.fileInput     = document.getElementById( 'masterquiz-file-input' );
		el.fileInfo      = document.getElementById( 'masterquiz-file-info' );
		el.fileName      = document.getElementById( 'masterquiz-file-name' );
		el.fileSize      = document.getElementById( 'masterquiz-file-size' );
		el.removeFile    = document.getElementById( 'masterquiz-remove-file' );
		el.numQuestions   = document.getElementById( 'masterquiz-num-questions' );
		el.quizMode      = document.getElementById( 'masterquiz-quiz-mode' );
		el.generateBtn   = document.getElementById( 'masterquiz-generate-btn' );
		el.progress      = document.getElementById( 'masterquiz-progress' );
		el.progressBar   = document.getElementById( 'masterquiz-progress-bar' );
		el.progressText  = document.getElementById( 'masterquiz-progress-text' );
		el.message       = document.getElementById( 'masterquiz-message' );
		el.results       = document.getElementById( 'masterquiz-results' );
		el.questionsWrap = document.getElementById( 'masterquiz-questions-container' );
		el.navigation    = document.getElementById( 'masterquiz-navigation' );
		el.prevBtn       = document.getElementById( 'masterquiz-prev-btn' );
		el.nextBtn       = document.getElementById( 'masterquiz-next-btn' );
		el.counter       = document.getElementById( 'masterquiz-question-counter' );
		el.exportBtn     = document.getElementById( 'masterquiz-export-btn' );
		el.exportModal   = document.getElementById( 'masterquiz-export-modal' );
		el.exportClose   = document.getElementById( 'masterquiz-export-close' );
		el.createLdBtn   = document.getElementById( 'masterquiz-create-ld-btn' );
		el.ldResult      = document.getElementById( 'masterquiz-learndash-result' );
		el.newQuizBtn    = document.getElementById( 'masterquiz-new-quiz-btn' );
	}

	/* =========================================================
	   Utility helpers
	   ========================================================= */

	/**
	 * Escape HTML entities to prevent XSS in dynamic content.
	 */
	function escapeHtml( text ) {
		var d       = document.createElement( 'div' );
		d.textContent = String( text || '' );
		return d.innerHTML;
	}

	/**
	 * Validate a File object: must be PDF within max size.
	 */
	function validateFile( file ) {
		if ( ! file || typeof file.name !== 'string' ) {
			return { ok: false, error: i18n.invalidFileType || 'Please select a PDF file.' };
		}
		var name  = file.name.toLowerCase();
		var type  = ( file.type || '' ).toLowerCase();
		var isPdf = ( type === 'application/pdf' || type === 'application/x-pdf' || name.slice( -4 ) === '.pdf' );
		if ( ! isPdf ) {
			return { ok: false, error: i18n.invalidFileType || 'Please select a PDF file.' };
		}
		if ( file.size > cfg.maxFileSize ) {
			var mb = Math.round( cfg.maxFileSize / 1024 / 1024 );
			return { ok: false, error: ( i18n.fileTooLarge || 'File is too large. Maximum size is' ) + ' ' + mb + ' MB.' };
		}
		return { ok: true };
	}

	/**
	 * Show an error / success message.
	 */
	function showMessage( text, type ) {
		if ( ! el.message ) {
			return;
		}
		el.message.textContent = text;
		el.message.className   = 'masterquiz-message visible ' + ( type || 'error' );
	}

	function hideMessage() {
		if ( el.message ) {
			el.message.className = 'masterquiz-message';
			el.message.textContent = '';
		}
	}

	/**
	 * Update progress bar + text.
	 */
	function setProgress( percent, text ) {
		if ( el.progressBar ) {
			el.progressBar.style.width = Math.min( 100, Math.max( 0, percent ) ) + '%';
		}
		if ( el.progressText && text ) {
			el.progressText.textContent = text;
		}
	}

	function showProgress() {
		if ( el.progress ) {
			el.progress.className = 'masterquiz-progress visible';
		}
	}

	function hideProgress() {
		if ( el.progress ) {
			el.progress.className = 'masterquiz-progress';
		}
		setProgress( 0, '' );
	}

	/**
	 * Toggle the Generate button state.
	 */
	function setGenerateEnabled( enabled ) {
		if ( el.generateBtn ) {
			el.generateBtn.disabled  = ! enabled;
			el.generateBtn.textContent = enabled
				? ( i18n.generateQuiz || 'Generate Quiz' )
				: ( i18n.generating_btn || 'Generating...' );
		}
	}

	/**
	 * Perform a WP-AJAX request.
	 *
	 * @param {string}   action   The `action` parameter for admin-ajax.php.
	 * @param {FormData} formData Form data payload.
	 * @return {Promise<Object>}  Parsed JSON response.
	 */
	function wpAjax( action, formData ) {
		if ( ! ( formData instanceof FormData ) ) {
			formData = new FormData();
		}
		formData.append( 'action', action );
		formData.append( 'nonce', cfg.nonce );

		return fetch( cfg.ajaxUrl, {
			method: 'POST',
			credentials: 'same-origin',
			body: formData,
		} )
			.then( function ( res ) {
				if ( ! res.ok ) {
					throw new Error( 'Server responded with ' + res.status );
				}
				return res.json();
			} )
			.then( function ( json ) {
				if ( json.success === false ) {
					throw new Error( ( json.data && json.data.message ) || 'Request failed.' );
				}
				return json.data || json;
			} );
	}

	/* =========================================================
	   File selection / Dropzone
	   ========================================================= */

	/**
	 * Format file size in human-readable units.
	 */
	function formatFileSize( bytes ) {
		if ( bytes < 1024 ) {
			return bytes + ' B';
		}
		if ( bytes < 1024 * 1024 ) {
			return ( bytes / 1024 ).toFixed( 1 ) + ' KB';
		}
		return ( bytes / 1024 / 1024 ).toFixed( 2 ) + ' MB';
	}


	/**
	 * Upload PDF as soon as the user selects it so Generate can start immediately.
	 */
	function uploadFileInBackground( file ) {
		if ( uploadInProgress && uploadPromise ) {
			return uploadPromise;
		}
		uploadInProgress = true;
		fileUploaded     = false;

		var uploadData = new FormData();
		uploadData.append( 'pdf_file', file );

		uploadPromise = wpAjax( 'masterquiz_upload', uploadData )
			.then( function () {
				fileUploaded     = true;
				uploadInProgress = false;
			} )
			.catch( function ( err ) {
				fileUploaded     = false;
				uploadInProgress = false;
				uploadPromise    = null;
				throw err;
			} );

		return uploadPromise;
	}

	function handleFileSelect( file ) {
		var check = validateFile( file );
		if ( ! check.ok ) {
			showMessage( check.error, 'error' );
			return;
		}
		selectedFile = file;
		if ( el.fileName ) {
			el.fileName.textContent = file.name;
		}
		if ( el.fileSize ) {
			el.fileSize.textContent = formatFileSize( file.size );
		}
		if ( el.fileInfo ) {
			el.fileInfo.className = 'masterquiz-file-info visible';
		}
		if ( el.dropContent ) {
			el.dropContent.style.display = 'none';
		}
		setGenerateEnabled( true );
		hideMessage();
		uploadFileInBackground( file );
	}

	function removeFile() {
		selectedFile     = null;
		fileUploaded     = false;
		uploadInProgress = false;
		uploadPromise    = null;
		if ( el.fileInput ) {
			el.fileInput.value = '';
		}
		if ( el.fileInfo ) {
			el.fileInfo.className = 'masterquiz-file-info';
		}
		if ( el.dropContent ) {
			el.dropContent.style.display = '';
		}
		setGenerateEnabled( false );
	}

	function bindDropzone() {
		if ( ! el.dropzone || ! el.fileInput ) {
			return;
		}

		// Click to browse.
		el.dropzone.addEventListener( 'click', function ( e ) {
			if ( e.target.closest( '#masterquiz-remove-file' ) || e.target.closest( '#masterquiz-file-info' ) ) {
				return;
			}
			if ( selectedFile ) {
				return;
			}
			el.fileInput.click();
		} );

		// File input change.
		el.fileInput.addEventListener( 'change', function ( e ) {
			if ( e.target.files && e.target.files.length ) {
				handleFileSelect( e.target.files[ 0 ] );
			}
			e.target.value = '';
		} );

		// Drag & drop.
		el.dropzone.addEventListener( 'dragover', function ( e ) {
			e.preventDefault();
			el.dropzone.classList.add( 'dragover' );
		} );
		el.dropzone.addEventListener( 'dragleave', function () {
			el.dropzone.classList.remove( 'dragover' );
		} );
		el.dropzone.addEventListener( 'drop', function ( e ) {
			e.preventDefault();
			el.dropzone.classList.remove( 'dragover' );
			if ( e.dataTransfer.files.length ) {
				handleFileSelect( e.dataTransfer.files[ 0 ] );
			}
		} );

		// Remove file button.
		if ( el.removeFile ) {
			el.removeFile.addEventListener( 'click', function ( e ) {
				e.stopPropagation();
				e.preventDefault();
				removeFile();
			} );
		}
	}

	/* =========================================================
	   Quiz Generation Flow
	   ========================================================= */

	function startGeneration() {
		if ( generationRunning ) {
			return;
		}
		if ( ! selectedFile ) {
			showMessage( i18n.selectFile || 'Please select a PDF file first.', 'error' );
			return;
		}

		// Validate question types.
		var typeCheckboxes = document.querySelectorAll( 'input[name="masterquiz_question_types[]"]:checked' );
		var types = [];
		typeCheckboxes.forEach( function ( cb ) {
			types.push( cb.value );
		} );
		if ( types.length === 0 ) {
			showMessage( i18n.selectQuestionType || 'Please select at least one question type.', 'error' );
			return;
		}

		var numQ = el.numQuestions ? parseInt( el.numQuestions.value, 10 ) : 5;
		numQ = Math.max( cfg.minQuestions || 3, Math.min( cfg.maxQuestions || 12, numQ ) );

		var mode = el.quizMode ? el.quizMode.value : ( cfg.defaultMode || 'fast' );

		generationRunning = true;
		hideMessage();
		setGenerateEnabled( false );
		showProgress();

		// Hide previous results.
		if ( el.results ) {
			el.results.className = 'masterquiz-results';
		}

		function startGenerationJob() {
			setProgress( 15, i18n.generating || 'Generating quiz...' );

			var genData = new FormData();
			genData.append( 'quiz_title', selectedFile.name.replace( /\.pdf$/i, '' ) );
			genData.append( 'num_questions', numQ );
			genData.append( 'quiz_mode', mode );
			types.forEach( function ( t ) {
				genData.append( 'question_types[]', t );
			} );

			return wpAjax( 'masterquiz_generate', genData );
		}

		function onJobStarted( data ) {
			currentJobId = data.job_id;
			setProgress( 20, i18n.generating || 'Generating quiz...' );
			pollJobStatus();
		}

		function onGenerationError( err ) {
			generationRunning = false;
			hideProgress();
			setGenerateEnabled( true );
			showMessage( err.message || ( i18n.failed || 'Quiz generation failed. Please try again.' ), 'error' );
		}

		// PDF uploads on file select; only wait if upload is still in flight.
		if ( fileUploaded ) {
			startGenerationJob().then( onJobStarted ).catch( onGenerationError );
		} else if ( uploadInProgress && uploadPromise ) {
			setProgress( 5, i18n.uploading || 'Uploading PDF...' );
			uploadPromise
				.then( function () { return startGenerationJob(); } )
				.then( onJobStarted )
				.catch( onGenerationError );
		} else {
			setProgress( 5, i18n.uploading || 'Uploading PDF...' );
			uploadFileInBackground( selectedFile )
				.then( function () { return startGenerationJob(); } )
				.then( onJobStarted )
				.catch( onGenerationError );
		}
	}

	/* =========================================================
	   Job Status Polling
	   ========================================================= */

	function pollJobStatus() {
		if ( ! currentJobId ) {
			return;
		}

		var formData = new FormData();
		formData.append( 'job_id', currentJobId );

		wpAjax( 'masterquiz_job_status', formData )
			.then( function ( data ) {
				var status   = data.status || 'queued';
				var progress = parseInt( data.progress, 10 ) || 0;
				var message  = data.message || '';

				if ( ! message.includes( '%' ) && progress > 0 ) {
					message += ' ' + progress + '%';
				}

				setProgress( progress, message || ( i18n.generating || 'Generating quiz...' ) );

				if ( status === 'completed' ) {
					onJobCompleted( data );
					return;
				}

				if ( status === 'failed' ) {
					onJobFailed( data );
					return;
				}

				// Schedule next poll (1.5 seconds).
				pollTimer = setTimeout( pollJobStatus, 1500 );
			} )
			.catch( function ( err ) {
				// Retry on transient errors, up to 5 min total.
				pollTimer = setTimeout( pollJobStatus, 3000 );
			} );
	}

	function stopPolling() {
		if ( pollTimer ) {
			clearTimeout( pollTimer );
			pollTimer = null;
		}
	}

	function onJobCompleted( data ) {
		stopPolling();
		generationRunning = false;
		setProgress( 100, i18n.completed || 'Quiz generated successfully!' );

		setTimeout( function () {
			hideProgress();
		}, 800 );

		setGenerateEnabled( true );

		if ( data.quiz ) {
			quizData = data.quiz;
			displayQuizResults( quizData );
		} else {
			showMessage( i18n.completed || 'Quiz generated successfully!', 'success' );
		}
	}

	function onJobFailed( data ) {
		stopPolling();
		generationRunning = false;
		hideProgress();
		setGenerateEnabled( true );
		showMessage( data.error || ( i18n.failed || 'Quiz generation failed. Please try again.' ), 'error' );
	}

	/* =========================================================
	   Display Quiz Results
	   ========================================================= */

	function displayQuizResults( qData ) {
		quizData = qData;
		allQuestions = [];

		if ( qData.questions && Array.isArray( qData.questions ) ) {
			allQuestions = qData.questions;
		} else if ( Array.isArray( qData ) ) {
			allQuestions = qData;
		}

		if ( allQuestions.length === 0 ) {
			showMessage( 'No questions found in quiz data.', 'error' );
			return;
		}

		currentQIndex = 0;
		renderQuestion( 0 );
		updateNav();

		// Show results section.
		if ( el.results ) {
			el.results.className = 'masterquiz-results visible';
		}

		// Show navigation if more than one question.
		if ( el.navigation ) {
			el.navigation.style.display = allQuestions.length > 1 ? '' : 'none';
		}

		// Scroll to results.
		setTimeout( function () {
			if ( el.results ) {
				el.results.scrollIntoView( { behavior: 'smooth', block: 'start' } );
			}
		}, 100 );
	}

	/* =========================================================
	   Render a single question card
	   ========================================================= */

	function renderQuestion( index ) {
		if ( ! el.questionsWrap || index < 0 || index >= allQuestions.length ) {
			return;
		}

		var q             = allQuestions[ index ];
		var questionText  = q.question_text || q.question || '';
		var questionType  = q.type || 'multiple_choice';
		var options       = q.options || [];
		var correctAnswer = q.correct_answer || '';
		var explanation   = q.explanation || '';
		var hint          = q.hint || '';
		var cogLevel      = q.cognitive_level || '';
		var points        = q.points || '';
		var modelAnswer   = q.model_answer || '';
		var rubric        = q.rubric_criteria || [];

		var keywords = q.concept_tags || q.keywords || q.tags || q.topics || [];

		var html = '<div class="masterquiz-question-card">';

		// Question number.
		html += '<div class="masterquiz-question-number">';
		html += escapeHtml( ( i18n.question || 'Question' ) + ' ' + ( index + 1 ) + ' ' + ( i18n.of || 'of' ) + ' ' + allQuestions.length );
		html += '</div>';

		// Header badges.
		html += '<div class="masterquiz-question-header">';
		html += '<div class="masterquiz-question-badges">';
		html += '<span class="masterquiz-badge masterquiz-badge-type">' + escapeHtml( questionType.replace( /_/g, ' ' ) ) + '</span>';
		if ( points ) {
			html += '<span class="masterquiz-badge masterquiz-badge-points">' + escapeHtml( points ) + ' ' + escapeHtml( i18n.points || 'points' ) + '</span>';
		}
		if ( cogLevel ) {
			html += '<span class="masterquiz-badge masterquiz-badge-level">' + escapeHtml( cogLevel ) + '</span>';
		}
		html += '</div></div>';

		// Keyword / topic tags.
		if ( keywords.length > 0 ) {
			html += '<div class="masterquiz-keyword-tags">';
			keywords.forEach( function ( kw ) {
				html += '<span class="masterquiz-keyword-tag">' + escapeHtml( kw ) + '</span>';
			} );
			html += '</div>';
		}

		// Question text.
		html += '<div class="masterquiz-question-text">' + escapeHtml( questionText ) + '</div>';

		// Hint.
		if ( hint ) {
			html += '<div class="masterquiz-hint"><strong>' + escapeHtml( i18n.hint || 'Hint' ) + ':</strong> ' + escapeHtml( hint ) + '</div>';
		}

		// Options (MCQ / True-False).
		if ( options.length > 0 ) {
			html += '<ul class="masterquiz-options">';
			options.forEach( function ( option, oi ) {
				var optText   = typeof option === 'string' ? option : ( option.text || String( option ) );
				var isCorrect = option === correctAnswer || ( typeof option === 'object' && option.correct );
				var label     = String.fromCharCode( 65 + oi );
				var rationale = ( typeof option === 'object' && option.rationale ) ? option.rationale : '';
				var cls       = 'masterquiz-option' + ( isCorrect ? ' correct' : '' );

				html += '<li class="' + cls + '">';
				html += '<span class="masterquiz-option-label">' + label + '.</span> ' + escapeHtml( optText );
				if ( isCorrect ) {
					html += ' <strong>(' + escapeHtml( i18n.correct || 'Correct' ) + ')</strong>';
				}
				if ( rationale ) {
					html += '<div class="masterquiz-explanation" style="margin-top:6px;">' + escapeHtml( rationale ) + '</div>';
				}
				html += '</li>';
			} );
			html += '</ul>';
		}

		// Model answer (essay).
		if ( modelAnswer ) {
			html += '<div class="masterquiz-model-answer">';
			html += '<h4>' + escapeHtml( i18n.modelAnswer || 'Model Answer' ) + '</h4>';
			html += '<p>' + escapeHtml( modelAnswer ) + '</p>';
			html += '</div>';
		}

		// Rubric criteria.
		if ( rubric.length > 0 ) {
			html += '<div class="masterquiz-explanation" style="border-left-color:#8b5cf6;">';
			html += '<strong>Rubric:</strong><ul style="margin:6px 0 0 18px;">';
			rubric.forEach( function ( c ) {
				html += '<li>' + escapeHtml( c ) + '</li>';
			} );
			html += '</ul></div>';
		}

		// Explanation.
		if ( explanation ) {
			html += '<div class="masterquiz-explanation"><strong>Explanation:</strong> ' + escapeHtml( explanation ) + '</div>';
		}

		html += '</div>'; // close card

		el.questionsWrap.innerHTML = html;
	}

	/* =========================================================
	   Navigation
	   ========================================================= */

	function updateNav() {
		if ( el.prevBtn ) {
			el.prevBtn.disabled = ( currentQIndex <= 0 );
		}
		if ( el.nextBtn ) {
			el.nextBtn.disabled = ( currentQIndex >= allQuestions.length - 1 );
		}
		if ( el.counter ) {
			el.counter.textContent = ( i18n.question || 'Question' ) + ' ' + ( currentQIndex + 1 ) + ' ' + ( i18n.of || 'of' ) + ' ' + allQuestions.length;
		}
	}

	function bindNavigation() {
		if ( el.prevBtn ) {
			el.prevBtn.addEventListener( 'click', function () {
				if ( currentQIndex > 0 ) {
					currentQIndex--;
					renderQuestion( currentQIndex );
					updateNav();
				}
			} );
		}
		if ( el.nextBtn ) {
			el.nextBtn.addEventListener( 'click', function () {
				if ( currentQIndex < allQuestions.length - 1 ) {
					currentQIndex++;
					renderQuestion( currentQIndex );
					updateNav();
				}
			} );
		}
	}

	/* =========================================================
	   Export
	   ========================================================= */

	function bindExport() {
		// Open modal.
		if ( el.exportBtn ) {
			el.exportBtn.addEventListener( 'click', function () {
				if ( el.exportModal ) {
					el.exportModal.className = 'masterquiz-export-modal visible';
				}
			} );
		}

		// Close modal.
		if ( el.exportClose ) {
			el.exportClose.addEventListener( 'click', function () {
				if ( el.exportModal ) {
					el.exportModal.className = 'masterquiz-export-modal';
				}
			} );
		}

		// Close modal on backdrop click.
		if ( el.exportModal ) {
			el.exportModal.addEventListener( 'click', function ( e ) {
				if ( e.target === el.exportModal ) {
					el.exportModal.className = 'masterquiz-export-modal';
				}
			} );
		}

		// Format buttons.
		var formatBtns = document.querySelectorAll( '.masterquiz-export-format-btn' );
		formatBtns.forEach( function ( btn ) {
			btn.addEventListener( 'click', function () {
				var format = this.getAttribute( 'data-format' );
				if ( ! format || ! currentJobId ) {
					return;
				}
				exportQuiz( format );
			} );
		} );
	}

	function exportQuiz( format ) {
		if ( ! currentJobId ) {
			showMessage( 'No quiz to export.', 'error' );
			return;
		}

		var formData = new FormData();
		formData.append( 'job_id', currentJobId );
		formData.append( 'format', format );
		formData.append( 'action', 'masterquiz_export' );
		formData.append( 'nonce', cfg.nonce );

		// Export triggers a file download via AJAX.
		fetch( cfg.ajaxUrl, {
			method: 'POST',
			credentials: 'same-origin',
			body: formData,
		} )
			.then( function ( res ) {
				var disposition = res.headers.get( 'content-disposition' ) || '';
				var contentType = res.headers.get( 'content-type' ) || '';

				// Content-Disposition: attachment means a file download regardless of content type.
				if ( disposition.indexOf( 'attachment' ) !== -1 ) {
					return res.blob().then( function ( blob ) {
						return { blob: blob, res: res };
					} );
				}

				// JSON without attachment header is an error response.
				if ( contentType.indexOf( 'application/json' ) !== -1 ) {
					return res.json().then( function ( json ) {
						throw new Error( ( json.data && json.data.message ) || 'Export failed.' );
					} );
				}

				if ( ! res.ok ) {
					throw new Error( 'Export failed: ' + res.statusText );
				}

				return res.blob().then( function ( blob ) {
					return { blob: blob, res: res };
				} );
			} )
			.then( function ( result ) {
				if ( ! result || ! result.blob ) {
					return;
				}

				// Determine filename from Content-Disposition or fallback.
				var disposition = result.res.headers.get( 'content-disposition' ) || '';
				var filenameMatch = disposition.match( /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/ );
				var filename = filenameMatch ? filenameMatch[ 1 ].replace( /['"]/g, '' ) : 'quiz_export.' + format;

				var url = window.URL.createObjectURL( result.blob );
				var a   = document.createElement( 'a' );
				a.href     = url;
				a.download = filename;
				document.body.appendChild( a );
				a.click();

				setTimeout( function () {
					window.URL.revokeObjectURL( url );
					document.body.removeChild( a );
				}, 200 );

				// Close modal.
				if ( el.exportModal ) {
					el.exportModal.className = 'masterquiz-export-modal';
				}
			} )
			.catch( function ( err ) {
				showMessage( err.message || 'Export failed.', 'error' );
			} );
	}

	/* =========================================================
	   LearnDash Quiz Creation
	   ========================================================= */

	function bindLearnDash() {
		if ( ! el.createLdBtn ) {
			return;
		}

		el.createLdBtn.addEventListener( 'click', function () {
			if ( ! currentJobId ) {
				showMessage( 'No quiz data available.', 'error' );
				return;
			}

			el.createLdBtn.disabled    = true;
			el.createLdBtn.textContent = i18n.generating_btn || 'Creating...';

			var formData = new FormData();
			formData.append( 'job_id', currentJobId );

			wpAjax( 'masterquiz_create_learndash_quiz', formData )
				.then( function ( data ) {
					el.createLdBtn.disabled    = false;
					el.createLdBtn.textContent = i18n.createLdQuiz || 'Create LearnDash Quiz';

					if ( el.ldResult ) {
						var link = data.edit_url
							? '<a href="' + escapeHtml( data.edit_url ) + '" target="_blank">' + escapeHtml( i18n.ldQuizCreated || 'LearnDash quiz created!' ) + '</a>'
							: escapeHtml( i18n.ldQuizCreated || 'LearnDash quiz created!' );
						el.ldResult.innerHTML  = link;
						el.ldResult.className  = 'masterquiz-learndash-result visible';
					}
				} )
				.catch( function ( err ) {
					el.createLdBtn.disabled    = false;
					el.createLdBtn.textContent = i18n.createLdQuiz || 'Create LearnDash Quiz';
					showMessage( err.message || 'LearnDash quiz creation failed.', 'error' );
				} );
		} );
	}

	/* =========================================================
	   New Quiz (reset)
	   ========================================================= */

	function bindNewQuiz() {
		if ( ! el.newQuizBtn ) {
			return;
		}

		el.newQuizBtn.addEventListener( 'click', function () {
			// Reset state.
			quizData      = null;
			allQuestions   = [];
			currentQIndex = 0;
			currentJobId  = null;

			// Hide results.
			if ( el.results ) {
				el.results.className = 'masterquiz-results';
			}
			if ( el.ldResult ) {
				el.ldResult.className = 'masterquiz-learndash-result';
			}

			hideMessage();
			removeFile();

			// Scroll to top of wrapper.
			if ( el.wrapper ) {
				el.wrapper.scrollIntoView( { behavior: 'smooth', block: 'start' } );
			}
		} );
	}

	/* =========================================================
	   Try with Sample PDF
	   ========================================================= */

	function bindTrySample() {
		var trySampleLink = document.getElementById( 'masterquiz-try-sample' );
		if ( ! trySampleLink || ! cfg.samplePdfUrl ) {
			return;
		}

		trySampleLink.addEventListener( 'click', function ( e ) {
			e.preventDefault();

			if ( generationRunning ) {
				return;
			}

			trySampleLink.style.pointerEvents = 'none';
			trySampleLink.style.opacity = '0.6';

			fetch( cfg.samplePdfUrl )
				.then( function ( res ) {
					if ( ! res.ok ) {
						throw new Error( 'Failed to load sample PDF.' );
					}
					return res.blob();
				} )
				.then( function ( blob ) {
					var file = new File( [ blob ], 'sample.pdf', { type: 'application/pdf' } );
					handleFileSelect( file );
					trySampleLink.style.pointerEvents = '';
					trySampleLink.style.opacity = '';

					// Auto-trigger generation.
					startGeneration();
				} )
				.catch( function ( err ) {
					trySampleLink.style.pointerEvents = '';
					trySampleLink.style.opacity = '';
					showMessage( err.message || 'Could not load sample PDF.', 'error' );
				} );
		} );
	}

	/* =========================================================
	   Initialize
	   ========================================================= */

	function init() {
		resolveElements();

		if ( ! el.wrapper ) {
			return;
		}

		// Set default quiz mode from config.
		if ( el.quizMode && cfg.defaultMode ) {
			el.quizMode.value = cfg.defaultMode;
		}

		bindDropzone();
		bindNavigation();
		bindExport();
		bindLearnDash();
		bindNewQuiz();
		bindTrySample();

		// Generate button.
		if ( el.generateBtn ) {
			el.generateBtn.addEventListener( 'click', function () {
				startGeneration();
			} );
		}
	}

	// Boot.
	if ( document.readyState === 'loading' ) {
		document.addEventListener( 'DOMContentLoaded', init );
	} else {
		init();
	}

	// Cleanup on page unload.
	window.addEventListener( 'beforeunload', function () {
		stopPolling();
	} );

} )();
