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

	// -------------------------------------------------------------------------
	// Translation history (localStorage)
	// -------------------------------------------------------------------------

	var HISTORY_KEY = 'eltmh_history';
	var MAX_HISTORY = 50;

	function loadHistory() {
		try {
			return JSON.parse( localStorage.getItem( HISTORY_KEY ) || '[]' );
		} catch ( e ) {
			return [];
		}
	}

	function saveHistory( history ) {
		try {
			localStorage.setItem( HISTORY_KEY, JSON.stringify( history ) );
		} catch ( e ) {
		}
	}

	function pushToHistory( text, result ) {
		var history = loadHistory();
		history.push( { text: text, result: result } );
		if ( history.length > MAX_HISTORY ) {
			history = history.slice( history.length - MAX_HISTORY );
		}
		saveHistory( history );
		return history.length - 1;
	}

	// -------------------------------------------------------------------------
	// Dictionary — lazy-loaded, shared across all widgets
	// -------------------------------------------------------------------------

	var dictData      = null;
	var dictLoading   = false;
	var dictCallbacks = [];

	function loadDict( dictUrl, callback ) {
		if ( dictData ) {
			callback( dictData ); return; }
		dictCallbacks.push( callback );
		if ( dictLoading ) {
			return; }
		dictLoading = true;

		fetch( dictUrl )
			.then(
				function ( r ) {
					return r.json(); }
			)
			.then(
				function ( data ) {
					dictData    = data;
					dictLoading = false;
					dictCallbacks.forEach(
						function ( cb ) {
							cb( dictData ); }
					);
					dictCallbacks = [];
				}
			)
			.catch(
				function () {
					dictLoading   = false;
					dictCallbacks = [];
				}
			);
	}

	// -------------------------------------------------------------------------
	// Segmentation — greedy longest-match (max 2 chars)
	// -------------------------------------------------------------------------

	function segmentChinese( text, dict ) {
		var segments = [];
		var i        = 0;

		while ( i < text.length ) {
			var matched = false;

			// Try longest match first (up to 6 chars), then shorter.
			for ( var len = 6; len >= 1; len-- ) {
				if ( i + len > text.length ) {
					continue; }
				var word = text.substring( i, i + len );
				if ( dict[ word ] ) {
					segments.push( { word: word, entry: dict[ word ] } );
					i      += len;
					matched = true;
					break;
				}
			}

			if ( ! matched ) {
				segments.push( { word: text[ i ], entry: null } );
				i++;
			}
		}

		return segments;
	}

	// -------------------------------------------------------------------------
	// Tooltip
	// -------------------------------------------------------------------------

	var tooltip = null;

	function getTooltip() {
		if ( tooltip ) {
			return tooltip; }
		tooltip           = document.createElement( 'div' );
		tooltip.className = 'eltmh-tooltip';
		document.body.appendChild( tooltip );
		return tooltip;
	}

	function showTooltip( span ) {
		var tt      = getTooltip();
		var pinyin  = span.dataset.p || '';
		var english = span.dataset.e || '';

		tt.innerHTML =
			'<span class="eltmh-tt-word">' + escHtml( span.textContent ) + '</span>' +
			'<span class="eltmh-tt-pinyin">' + escHtml( pinyin ) + '</span>' +
			'<span class="eltmh-tt-def">' + escHtml( english ) + '</span>';

		var rect         = span.getBoundingClientRect();
		tt.style.display = 'block';

		// Position below the character; flip above if near bottom of viewport.
		var top = rect.bottom + window.scrollY + 6;
		if ( rect.bottom + tt.offsetHeight + 10 > window.innerHeight ) {
			top = rect.top + window.scrollY - tt.offsetHeight - 6;
		}

		var left      = rect.left + window.scrollX;
		var maxLeft   = window.innerWidth + window.scrollX - tt.offsetWidth - 8;
		tt.style.left = Math.max( 0, Math.min( left, maxLeft ) ) + 'px';
		tt.style.top  = top + 'px';
	}

	function hideTooltip() {
		if ( tooltip ) {
			tooltip.style.display = 'none'; }
	}

	// -------------------------------------------------------------------------
	// Copy to clipboard
	// -------------------------------------------------------------------------

	function addCopyButton( span ) {
		// Remove any pre-existing copy button in the same parent row (may be inside the label).
		var parent = span.parentNode;
		var scope  = ( parent && parent.querySelector( '.eltmh-label' ) ) || parent;
		if ( scope ) {
			Array.prototype.forEach.call(
				scope.querySelectorAll( '.eltmh-copy' ),
				function ( b ) { b.remove(); }
			);
		}
		if ( ! span.textContent.trim() ) { return; }
		var btn       = document.createElement( 'button' );
		btn.type      = 'button';
		btn.className = 'eltmh-copy';
		btn.setAttribute( 'aria-label', 'Copy' );
		btn.textContent = '⎘'; // ⎘ clipboard symbol
		btn.addEventListener( 'click', function () {
			var text = span.textContent.trim();
			if ( ! navigator.clipboard ) { return; }
			navigator.clipboard.writeText( text ).then( function () {
				btn.textContent = 'Copied!';
				setTimeout( function () { btn.textContent = '⎘'; }, 1500 );
			} ).catch( function () {} );
		} );
		var label = parent && parent.querySelector( '.eltmh-label' );
		if ( label ) {
			label.appendChild( btn );
		} else {
			span.parentNode.insertBefore( btn, span.nextSibling );
		}
	}

	document.addEventListener(
		'mouseover',
		function ( e ) {
			if ( e.target.classList && e.target.classList.contains( 'eltmh-word' ) ) {
				showTooltip( e.target );
			} else {
				hideTooltip();
			}
		}
	);

	document.addEventListener( 'scroll', hideTooltip, true );

	// -------------------------------------------------------------------------
	// Annotation — wrap segmented words in <span> elements
	// -------------------------------------------------------------------------

	function escHtml( str ) {
		return ( str || '' )
			.replace( /&/g, '&amp;' )
			.replace( /</g, '&lt;' )
			.replace( />/g, '&gt;' )
			.replace( /"/g, '&quot;' );
	}

	function escAttr( str ) {
		return escHtml( str || '' ).replace( /'/g, '&#39;' );
	}

	function annotateEl( el, dict ) {
		var text = el.textContent;
		if ( ! text ) {
			return; }

		var segments = segmentChinese( text, dict );
		var html     = segments.map(
			function ( seg ) {
				if ( seg.entry ) {
						return '<span class="eltmh-word" data-p="' + escAttr( seg.entry[ 0 ] ) +
					'" data-e="' + escAttr( seg.entry[ 1 ] ) + '">' +
					escHtml( seg.word ) + '</span>';
				}
				return escHtml( seg.word );
			}
		).join( '' );

		el.innerHTML = html;
	}

	function annotateWidget( widget, dict ) {
		[ '.eltmh-chinese', '.eltmh-bopomofo' ].forEach(
			function ( sel ) {
				var el = widget.querySelector( sel );
				if ( el && el.textContent ) {
						annotateEl( el, dict );
				}
			}
		);
	}

	// -------------------------------------------------------------------------
	// Config helper
	// -------------------------------------------------------------------------

	function getConfig( widget ) {
		var restUrl = widget.dataset.restUrl || ( typeof eltmhData !== 'undefined' ? eltmhData.restUrl : '' );
		var nonce   = widget.dataset.nonce || ( typeof eltmhData !== 'undefined' ? eltmhData.nonce : '' );
		var dictUrl = widget.dataset.dictUrl || '';
		return { restUrl: restUrl, nonce: nonce, dictUrl: dictUrl };
	}

	// -------------------------------------------------------------------------
	// Result rendering
	// -------------------------------------------------------------------------

	function renderResult( widget, sourceText, data, config ) {
		var el;
		el = widget.querySelector( '.eltmh-source-language' ); if ( el ) {
			el.textContent = data.source_language || ''; }
		el = widget.querySelector( '.eltmh-source-text' );     if ( el ) {
			el.textContent = sourceText; }
		el = widget.querySelector( '.eltmh-chinese' );         if ( el ) {
			el.textContent = data.chinese || ''; addCopyButton( el ); }
		el = widget.querySelector( '.eltmh-pinyin' );          if ( el ) {
			el.textContent = data.pinyin || ''; addCopyButton( el ); }
		el = widget.querySelector( '.eltmh-bopomofo' );        if ( el ) {
			el.textContent = data.chinese || ''; addCopyButton( el ); }

		var englishRow = widget.querySelector( '.eltmh-english-row' );
		if ( data.english && englishRow ) {
			el = widget.querySelector( '.eltmh-english' );
			if ( el ) {
				el.textContent = data.english; addCopyButton( el ); }
			englishRow.style.display = '';
		} else if ( englishRow ) {
			englishRow.style.display = 'none';
		}

		widget.querySelector( '.eltmh-results' ).style.display = '';

		// Annotate Chinese text with dictionary tooltips.
		if ( data.chinese && config && config.dictUrl ) {
			if ( dictData ) {
				annotateWidget( widget, dictData );
			} else {
				loadDict(
					config.dictUrl,
					function ( dict ) {
						annotateWidget( widget, dict );
					}
				);
			}
		}
	}

	// -------------------------------------------------------------------------
	// Widget initialisation
	// -------------------------------------------------------------------------

	function initWidget( widget ) {
		var form         = widget.querySelector( '.eltmh-form' );
		var input        = widget.querySelector( '.eltmh-input' );
		var clearBtn     = widget.querySelector( '.eltmh-clear' );
		var spinner      = widget.querySelector( '.eltmh-spinner' );
		var errorEl      = widget.querySelector( '.eltmh-error' );
		var navEl        = widget.querySelector( '.eltmh-history-nav' );
		var prevBtn      = widget.querySelector( '.eltmh-prev' );
		var nextBtn      = widget.querySelector( '.eltmh-next' );
		var posEl        = widget.querySelector( '.eltmh-history-pos' );
		var config       = getConfig( widget );
		var currentIndex = -1;
		var spinnerText  = spinner.textContent;

		function updateClearBtn() {
			if ( clearBtn ) {
				clearBtn.style.display = input.value.length ? '' : 'none';
			}
		}

		if ( clearBtn ) {
			clearBtn.addEventListener(
				'click',
				function () {
					input.value = '';
					input.focus();
					updateClearBtn();
					updateCharCount();
					// Hide results and clear all content spans.
					var results = widget.querySelector( '.eltmh-results' );
					if ( results ) { results.style.display = 'none'; }
					[ '.eltmh-source-text', '.eltmh-source-language', '.eltmh-chinese',
					  '.eltmh-pinyin', '.eltmh-bopomofo', '.eltmh-english' ].forEach(
						function ( sel ) {
							var el = widget.querySelector( sel );
							if ( el ) { el.textContent = ''; }
						}
					);
					Array.prototype.forEach.call(
						widget.querySelectorAll( '.eltmh-copy' ),
						function ( b ) { b.remove(); }
					);
					var englishRow = widget.querySelector( '.eltmh-english-row' );
					if ( englishRow ) { englishRow.style.display = 'none'; }
					// Move index past the end of history so Previous re-shows the last entry.
					currentIndex = loadHistory().length;
					updateNav();
				}
			);
		}

		input.addEventListener( 'input', updateClearBtn );
		updateClearBtn();

		// Counter row — version left, char count right, inserted after the textarea wrapper.
		var submitBtn   = form.querySelector( '.eltmh-submit' );
		var counterRow  = document.createElement( 'div' );
		counterRow.className = 'eltmh-counter-row';
		var versionEl   = document.createElement( 'span' );
		versionEl.className  = 'eltmh-version';
		versionEl.textContent = 'v' + ( widget.dataset.version || '' );
		var charCount   = document.createElement( 'span' );
		charCount.className  = 'eltmh-char-count';
		counterRow.appendChild( versionEl );
		counterRow.appendChild( charCount );
		var inputWrap = input.closest( '.eltmh-input-wrap' ) || input.parentNode;
		inputWrap.parentNode.insertBefore( counterRow, inputWrap.nextSibling );

		function updateCharCount() {
			var len = input.value.length;
			charCount.textContent = len + ' / 500';
			if ( len > 450 ) {
				charCount.classList.add( 'eltmh-char-over' );
			} else {
				charCount.classList.remove( 'eltmh-char-over' );
			}
			if ( submitBtn ) {
				submitBtn.disabled = len > 500;
			}
		}

		input.addEventListener( 'input', updateCharCount );
		updateCharCount();

		function updateNav() {
			var history = loadHistory();
			var atBlank = ( currentIndex >= history.length );
			// Show nav when history has 2+ entries, or when cleared with at least 1 entry to go back to.
			var show = navEl && ( history.length >= 2 || ( atBlank && history.length >= 1 ) );
			if ( ! show ) {
				if ( navEl ) {
					navEl.style.display = 'none'; }
				return;
			}
			navEl.style.display = '';
			if ( posEl ) {
				posEl.textContent = atBlank ? '— / ' + history.length : ( currentIndex + 1 ) + ' / ' + history.length; }
			if ( prevBtn ) {
				prevBtn.disabled = ( currentIndex <= 0 ); }
			if ( nextBtn ) {
				nextBtn.disabled = atBlank || ( currentIndex >= history.length - 1 ); }
		}

		function showEntry( idx ) {
			var history = loadHistory();
			var entry   = history[ idx ];
			if ( ! entry ) {
				return; }
			currentIndex = idx;
			input.value  = entry.text;
			updateClearBtn();
			renderResult( widget, entry.text, entry.result, config );
			updateNav();
		}

		// Render pre-cached result (shortcode with preset text) or restore last history entry.
		if ( widget.dataset.presetResult ) {
			try {
				renderResult( widget, input.value, JSON.parse( widget.dataset.presetResult ), config );
			} catch ( e ) {
			}
		} else {
			var initHistory = loadHistory();
			if ( initHistory.length > 0 ) {
				showEntry( initHistory.length - 1 );
			}
		}

		// Prefetch the dictionary in the background so first hover is instant.
		if ( config.dictUrl && ! dictData && ! dictLoading ) {
			loadDict( config.dictUrl, function () {} );
		}

		// On the front-end (no eltmhData), refresh the nonce to handle page-cached pages.
		if ( typeof eltmhData === 'undefined' && config.restUrl ) {
			var nonceUrl = config.restUrl.replace( /\/translate$/, '/nonce' );
			fetch( nonceUrl )
				.then(
					function ( r ) {
						return r.json(); }
				)
				.then(
					function ( data ) {
						if ( data.nonce ) {
							config.nonce = data.nonce; }
					}
				)
				.catch( function () {} );
		}

		if ( prevBtn ) {
			prevBtn.addEventListener(
				'click',
				function () {
					if ( currentIndex > 0 ) {
						showEntry( currentIndex - 1 ); }
				}
			);
		}

		if ( nextBtn ) {
			nextBtn.addEventListener(
				'click',
				function () {
					var history = loadHistory();
					if ( currentIndex < history.length - 1 ) {
						showEntry( currentIndex + 1 ); }
				}
			);
		}

		form.addEventListener(
			'submit',
			function ( e ) {
				e.preventDefault();

				var text = input.value.trim();
				if ( ! text ) {
					return; }
				if ( text.length > 500 ) { return; }

				spinner.style.display                                  = '';
				errorEl.style.display                                  = 'none';
				errorEl.textContent                                    = '';
				widget.querySelector( '.eltmh-results' ).style.display = 'none';

				fetch(
					config.restUrl,
					{
						method:  'POST',
						headers: {
							'Content-Type':  'application/json',
							'X-ELTMH-Nonce': config.nonce,
						},
						body: JSON.stringify( { text: text } ),
					}
				)
				.then(
					function ( response ) {
						return response.json(); }
				)
				.then(
					function ( data ) {
						if ( data.code ) {
							spinner.style.display = 'none';
							errorEl.textContent   = data.message || 'An error occurred.';
							errorEl.style.display = '';
						} else {
							spinner.textContent = 'Done!';
							setTimeout( function () {
								spinner.style.display = 'none';
								spinner.textContent   = spinnerText;
							}, 1000 );
							currentIndex = pushToHistory( text, data );
							renderResult( widget, text, data, config );
							updateNav();
						}
					}
				)
				.catch(
					function () {
						spinner.style.display = 'none';
						errorEl.textContent   = 'Request failed. Please check your connection and try again.';
						errorEl.style.display = '';
					}
				);
			}
		);
	}

	document.addEventListener(
		'DOMContentLoaded',
		function () {
			document.querySelectorAll( '.eltmh-translator-widget' ).forEach( initWidget );
		}
	);
}() );
