/**
 * File Path: assets/js/adminjs/mbs-import-progress.js
 *
 * MBS Import Progress — Shared Vanishing-Message Progress Module
 *
 * Provides a reusable progress tracker used by both the ZIP Archive Import
 * flow (mbs-archive-import-export.js) and the Tutorial Install flow
 * (mbs-tutorial-admin.js).
 *
 * UX contract:
 *   - One "current activity" line replaces itself on each step (vanishing).
 *   - Warnings/errors accumulate below the activity line and persist.
 *   - On complete(): bar hides after 2.5 s; msgArea hides too if no warnings.
 *   - On failed(): bar hides immediately; error appears in statusArea.
 *
 * Usage:
 *   var prog = MBSImportProgress.create({
 *       barWrap    : document.getElementById('my-bar-wrap'),
 *       barFill    : document.getElementById('my-bar-fill'),
 *       msgArea    : document.getElementById('my-msg-area'),
 *       statusArea : document.getElementById('my-status'),
 *   });
 *   prog.show();
 *   prog.setBar( 25 );
 *   prog.setMessage( 'Doing something\u2026' );
 *   prog.addWarning( 'Non-fatal issue.' );
 *   prog.complete( 'All done!' );
 *
 * All DOM elements are optional (null-safe).
 *
 * Exposes: window.MBSImportProgress
 *
 * @package MyBookShowroom
 * @since   2.1.0
 */

/* global window */
( function ( global ) {
	'use strict';

	// -------------------------------------------------------------------------
	// Utility
	// -------------------------------------------------------------------------

	/**
	 * Escape HTML special characters for safe innerHTML insertion.
	 *
	 * @param  {string} text  Raw string.
	 * @return {string}       HTML-escaped string.
	 */
	function escHtml( text ) {
		return String( text )
			.replace( /&/g, '&amp;' )
			.replace( /</g, '&lt;' )
			.replace( />/g, '&gt;' )
			.replace( /"/g, '&quot;' );
	}

	// -------------------------------------------------------------------------
	// Factory
	// -------------------------------------------------------------------------

	/**
	 * Create a progress tracker bound to specific DOM elements.
	 *
	 * @param  {Object}       opts
	 * @param  {Element|null} opts.barWrap    Wrapper element shown while progress
	 *                                         is active; hidden on complete / failed.
	 * @param  {Element|null} opts.barFill    Inner progress-bar fill element (width%).
	 * @param  {Element|null} opts.msgArea    Container div; module inserts a single
	 *                                         <p> for the current activity line and
	 *                                         appends <p> elements for each warning.
	 * @param  {Element|null} opts.statusArea Final result notice element.
	 * @return {Object}  Progress instance.
	 */
	function create( opts ) {
		var barWrap    = opts.barWrap    || null;
		var barFill    = opts.barFill    || null;
		var msgArea    = opts.msgArea    || null;
		var statusArea = opts.statusArea || null;

		/** @type {HTMLParagraphElement|null} */
		var _currentP  = null;

		/** @type {number|null} */
		var _fadeTimer = null;

		// ── Private helpers ─────────────────────────────────────────────────

		/**
		 * Return (creating if necessary) the single "current activity" <p>.
		 *
		 * The element is always the first child of msgArea so new warnings
		 * appended later appear below it.
		 *
		 * @return {HTMLParagraphElement|null}
		 */
		function _ensureCurrentP() {
			if ( ! msgArea ) { return null; }
			if ( ! _currentP ) {
				_currentP = document.createElement( 'p' );
				_currentP.className = 'mbs-prog-current';
				_currentP.style.cssText =
					'margin:2px 0 4px;font-size:0.875rem;color:#3c434a;';
				msgArea.insertBefore( _currentP, msgArea.firstChild );
			}
			return _currentP;
		}

		// ── Public API ──────────────────────────────────────────────────────

		/**
		 * Make the progress section visible (bar wrapper + message area).
		 * Call before the first setBar() or setMessage().
		 *
		 * @return {void}
		 */
		function show() {
			if ( barWrap )  { barWrap.style.display  = 'block'; }
			if ( msgArea )  { msgArea.style.display   = 'block'; }
		}

		/**
		 * Update the progress bar fill to the given percentage.
		 *
		 * @param  {number} pct  0-100
		 * @return {void}
		 */
		function setBar( pct ) {
			if ( barFill ) {
				barFill.style.width =
					Math.min( 100, Math.max( 0, pct ) ) + '%';
			}
		}

		/**
		 * Replace the current activity line with new text.
		 * Previous text disappears (vanishing-message UX).
		 *
		 * @param  {string} text
		 * @return {void}
		 */
		function setMessage( text ) {
			var p = _ensureCurrentP();
			if ( p ) { p.textContent = text; }
		}

		/**
		 * Append a persistent warning line below the current activity line.
		 * Warnings survive the 2.5 s fade that hides the activity line.
		 *
		 * @param  {string} text  Warning text (plain, will be HTML-escaped).
		 * @return {void}
		 */
		function addWarning( text ) {
			if ( ! msgArea ) { return; }
			var p = document.createElement( 'p' );
			p.className = 'mbs-prog-warn';
			p.style.cssText =
				'margin:2px 0;font-size:0.8rem;color:#8a6d3b;';
			p.textContent = '\u26a0 ' + text;
			msgArea.appendChild( p );
			if ( msgArea.style.display === 'none' ) {
				msgArea.style.display = 'block';
			}
		}

		/**
		 * Mark the operation as complete.
		 *
		 * Sets bar to 100%, shows a success notice in statusArea, then after
		 * 2.5 s hides barWrap and clears the activity line. If warnings exist
		 * the msgArea remains visible; otherwise it hides too.
		 *
		 * @param  {string} summary  Human-readable success summary.
		 * @return {void}
		 */
		function complete( summary ) {
			clearTimeout( _fadeTimer );
			setBar( 100 );
			setMessage( '' );
			if ( statusArea ) {
				statusArea.className = 'notice notice-success';
				statusArea.innerHTML = '<p>' + escHtml( summary ) + '</p>';
				statusArea.style.display = 'block';
			}
			var warnCount = msgArea
				? msgArea.querySelectorAll( '.mbs-prog-warn' ).length
				: 0;
			_fadeTimer = setTimeout( function () {
				if ( barWrap ) { barWrap.style.display = 'none'; }
				if ( _currentP ) { _currentP.textContent = ''; }
				if ( ! warnCount && msgArea ) {
					msgArea.style.display = 'none';
				}
			}, 2500 );
		}

		/**
		 * Mark the operation as failed.
		 *
		 * Clears the activity line, hides barWrap immediately, shows an error
		 * notice in statusArea. Accumulated warnings remain visible.
		 *
		 * @param  {string} msg  Human-readable error message.
		 * @return {void}
		 */
		function failed( msg ) {
			clearTimeout( _fadeTimer );
			setMessage( '' );
			if ( barWrap ) { barWrap.style.display = 'none'; }
			if ( statusArea ) {
				statusArea.className = 'notice notice-error';
				statusArea.innerHTML = '<p>' + escHtml( msg ) + '</p>';
				statusArea.style.display = 'block';
			}
		}

		/**
		 * Reset all UI to hidden/empty state, ready for a new operation.
		 *
		 * @return {void}
		 */
		function reset() {
			clearTimeout( _fadeTimer );
			_currentP  = null;
			_fadeTimer = null;
			setBar( 0 );
			if ( barWrap ) { barWrap.style.display = 'none'; }
			if ( msgArea ) {
				msgArea.innerHTML    = '';
				msgArea.style.display = 'none';
			}
			if ( statusArea ) {
				statusArea.style.display = 'none';
				statusArea.innerHTML     = '';
				statusArea.className     = '';
			}
		}

		return {
			show       : show,
			setBar     : setBar,
			setMessage : setMessage,
			addWarning : addWarning,
			complete   : complete,
			failed     : failed,
			reset      : reset,
		};
	}

	// -------------------------------------------------------------------------
	// Export
	// -------------------------------------------------------------------------

	global.MBSImportProgress = { create: create };

}( window ) );
