/**
 * Livada SEO — Metabox JS
 *
 * Handles:
 *   - Tab switching
 *   - Real-time character counters (title + description)
 *   - SERP preview (live updates)
 *   - OG image media picker (wp.media)
 *   - Simplified live SEO scoring
 *
 * Vanilla JS only (no jQuery). Runs after DOM ready.
 */

( function () {
	'use strict';

	// ── Helpers ───────────────────────────────────────────────────────────────

	/**
	 * Returns an element by id or null if not found.
	 * @param {string} id
	 * @returns {HTMLElement|null}
	 */
	function byId( id ) {
		return document.getElementById( id );
	}

	// ── Tab switching ─────────────────────────────────────────────────────────

	function initTabs() {
		var tabBtns = document.querySelectorAll( '.livada-seo-tab-btn' );
		var panels  = document.querySelectorAll( '.livada-seo-panel' );

		if ( ! tabBtns.length ) {
			return;
		}

		tabBtns.forEach( function ( btn ) {
			btn.addEventListener( 'click', function () {
				var target = btn.getAttribute( 'data-panel' );

				// Update buttons.
				tabBtns.forEach( function ( b ) {
					var active = b.getAttribute( 'data-panel' ) === target;
					b.classList.toggle( 'is-active', active );
					b.setAttribute( 'aria-selected', active ? 'true' : 'false' );
				} );

				// Update panels.
				panels.forEach( function ( panel ) {
					var id     = panel.getAttribute( 'id' ) || '';
					var active = id === 'livada-seo-panel-' + target;
					panel.classList.toggle( 'is-active', active );
				} );
			} );
		} );
	}

	// ── Character counters ────────────────────────────────────────────────────

	/**
	 * Applies a colour class to the counter element based on length ranges.
	 *
	 * @param {HTMLElement} counterEl  The counter div.
	 * @param {number}      len        Current string length.
	 * @param {number}      minGreen   Lower bound of green range.
	 * @param {number}      maxGreen   Upper bound of green range.
	 * @param {number}      minOrange  Outer lower bound (below minGreen).
	 * @param {number}      maxOrange  Outer upper bound (above maxGreen).
	 */
	function applyCounterColour( counterEl, len, minGreen, maxGreen, minOrange, maxOrange ) {
		counterEl.classList.remove( 'is-green', 'is-orange', 'is-red' );

		var cls;
		if ( len >= minGreen && len <= maxGreen ) {
			cls = 'is-green';
		} else if ( len >= minOrange && len <= maxOrange ) {
			cls = 'is-orange';
		} else {
			cls = 'is-red';
		}
		counterEl.classList.add( cls );
	}

	function updateTitleCounter() {
		var field   = byId( 'livada_seo_title' );
		var counter = byId( 'livada-seo-title-counter' );

		if ( ! field || ! counter ) {
			return;
		}

		var len = field.value.length;
		counter.textContent = len + ' / 60 ' + ( len === 1 ? 'character' : 'characters' );
		applyCounterColour( counter, len, 50, 60, 40, 70 );
	}

	function updateDescCounter() {
		var field   = byId( 'livada_seo_description' );
		var counter = byId( 'livada-seo-desc-counter' );

		if ( ! field || ! counter ) {
			return;
		}

		var len = field.value.length;
		counter.textContent = len + ' / 160 ' + ( len === 1 ? 'character' : 'characters' );
		applyCounterColour( counter, len, 120, 160, 100, 180 );
	}

	function initCounters() {
		var titleField = byId( 'livada_seo_title' );
		var descField  = byId( 'livada_seo_description' );

		if ( titleField ) {
			titleField.addEventListener( 'input', function () {
				updateTitleCounter();
				updateSerpPreview();
				updateLiveScore();
			} );
			updateTitleCounter();
		}

		if ( descField ) {
			descField.addEventListener( 'input', function () {
				updateDescCounter();
				updateSerpPreview();
				updateLiveScore();
			} );
			updateDescCounter();
		}
	}

	// ── SERP preview ──────────────────────────────────────────────────────────

	function updateSerpPreview() {
		var titleField = byId( 'livada_seo_title' );
		var descField  = byId( 'livada_seo_description' );

		// Title: use field value or fall back to the WordPress post title
		// (populated as the input placeholder attribute).
		var title = titleField ? ( titleField.value.trim() || titleField.getAttribute( 'placeholder' ) || '' ) : '';
		var desc  = descField  ? descField.value.trim() : '';

		// URL from inline data set by wp_add_inline_script.
		var permalink = ( window.livadaSEO && window.livadaSEO.permalink ) ? window.livadaSEO.permalink : window.location.href;

		// Apply to both desktop and mobile preview blocks.
		[ 'livada-seo-serp-title', 'livada-seo-serp-title-mobile' ].forEach( function ( id ) {
			var el = byId( id );
			if ( el ) { el.textContent = title; }
		} );

		[ 'livada-seo-serp-url', 'livada-seo-serp-url-mobile' ].forEach( function ( id ) {
			var el = byId( id );
			if ( el ) { el.textContent = permalink; }
		} );

		[ 'livada-seo-serp-desc', 'livada-seo-serp-desc-mobile' ].forEach( function ( id ) {
			var el = byId( id );
			if ( el ) { el.textContent = desc; }
		} );
	}

	function initSerpPreview() {
		updateSerpPreview();

		var keywordField = byId( 'livada_seo_focus_keyword' );
		if ( keywordField ) {
			keywordField.addEventListener( 'input', function () {
				updateLiveScore();
				scheduleLinkSuggestions();
			} );
		}

		// Device toggle (Desktop / Mobile).
		var btns       = document.querySelectorAll( '.livada-seo-serp-device-btn' );
		var serpDesk   = byId( 'livada-seo-serp' );
		var serpMobile = byId( 'livada-seo-serp-mobile' );

		btns.forEach( function ( btn ) {
			btn.addEventListener( 'click', function () {
				var device = btn.getAttribute( 'data-device' );

				btns.forEach( function ( b ) {
					var active = b.getAttribute( 'data-device' ) === device;
					b.classList.toggle( 'is-active', active );
					b.setAttribute( 'aria-selected', active ? 'true' : 'false' );
				} );

				if ( serpDesk )   { serpDesk.classList.toggle(   'is-hidden', device !== 'desktop' ); }
				if ( serpMobile ) { serpMobile.classList.toggle( 'is-hidden', device !== 'mobile'  ); }
			} );
		} );
	}

	// ── Live SEO scoring ──────────────────────────────────────────────────────

	/**
	 * Builds a simple dot + message list item.
	 *
	 * @param {string} status  'green' | 'orange' | 'red'
	 * @param {string} message Human-readable check result.
	 * @returns {HTMLLIElement}
	 */
	function makeCheckItem( status, message ) {
		var li   = document.createElement( 'li' );
		var dot  = document.createElement( 'span' );
		var text = document.createElement( 'span' );

		dot.className     = 'livada-seo-score__dot is-' + status;
		text.textContent  = message;

		li.appendChild( dot );
		li.appendChild( text );
		return li;
	}

	function updateLiveScore() {
		var list = byId( 'livada-seo-live-checks' );
		if ( ! list ) {
			return;
		}

		var titleField   = byId( 'livada_seo_title' );
		var descField    = byId( 'livada_seo_description' );
		var keywordField = byId( 'livada_seo_focus_keyword' );

		var title   = titleField   ? titleField.value.trim()   : '';
		var desc    = descField    ? descField.value.trim()    : '';
		var keyword = keywordField ? keywordField.value.trim().toLowerCase() : '';

		var checks = [];

		// ── Title length check ────────────────────────────────────────────────
		var titleLen = title.length;
		if ( titleLen === 0 ) {
			checks.push( { status: 'orange', message: 'Meta title is empty (post title will be used).' } );
		} else if ( titleLen >= 50 && titleLen <= 60 ) {
			checks.push( { status: 'green',  message: 'Meta title length is ideal (' + titleLen + ' chars).' } );
		} else if ( titleLen >= 40 && titleLen <= 70 ) {
			checks.push( { status: 'orange', message: 'Meta title length (' + titleLen + ' chars) could be closer to 50–60.' } );
		} else {
			checks.push( { status: 'red',    message: 'Meta title length (' + titleLen + ' chars) is outside recommended range.' } );
		}

		// ── Description length check ──────────────────────────────────────────
		var descLen = desc.length;
		if ( descLen === 0 ) {
			checks.push( { status: 'orange', message: 'Meta description is empty.' } );
		} else if ( descLen >= 120 && descLen <= 160 ) {
			checks.push( { status: 'green',  message: 'Meta description length is ideal (' + descLen + ' chars).' } );
		} else if ( descLen >= 100 && descLen <= 180 ) {
			checks.push( { status: 'orange', message: 'Meta description length (' + descLen + ' chars) could be closer to 120–160.' } );
		} else {
			checks.push( { status: 'red',    message: 'Meta description length (' + descLen + ' chars) is outside recommended range.' } );
		}

		// ── Keyword in title ──────────────────────────────────────────────────
		if ( keyword ) {
			if ( title.toLowerCase().indexOf( keyword ) !== -1 ) {
				checks.push( { status: 'green',  message: 'Focus keyword found in meta title.' } );
			} else {
				checks.push( { status: 'red',    message: 'Focus keyword not found in meta title.' } );
			}
		} else {
			checks.push( { status: 'orange', message: 'No focus keyword set — keyword checks skipped.' } );
		}

		// ── Keyword in description ────────────────────────────────────────────
		if ( keyword && desc ) {
			if ( desc.toLowerCase().indexOf( keyword ) !== -1 ) {
				checks.push( { status: 'green',  message: 'Focus keyword found in meta description.' } );
			} else {
				checks.push( { status: 'orange', message: 'Focus keyword not found in meta description.' } );
			}
		}

		// ── Live Flesch reading-ease on the meta description ─────────────────
		// Mirrors the PHP heuristic in class-analysis.php so the metabox shows
		// the same band the on-save analyser will report.
		if ( desc.length >= 60 ) {
			var fle = computeFlesch( desc );
			if ( fle >= 60 ) {
				checks.push( { status: 'green',  message: 'Description readability ' + fle + '/100 (plain language).' } );
			} else if ( fle >= 30 ) {
				checks.push( { status: 'orange', message: 'Description readability ' + fle + '/100 (fairly difficult).' } );
			} else {
				checks.push( { status: 'red',    message: 'Description readability ' + fle + '/100 (very difficult).' } );
			}
		}

		// ── Live keyword density on the description (cheap metabox-side proxy) ──
		// We only have the meta description in the metabox context, not the full
		// post content, so this is a directional indicator — the on-save
		// analyser does the real, content-wide computation.
		if ( keyword && desc.length > 0 ) {
			var density = computeKeywordDensity( desc, keyword );
			var dStr = density.toFixed( 1 ) + '%';
			if ( density >= 1.0 && density <= 3.0 ) {
				checks.push( { status: 'green',  message: 'Keyword density in description: ' + dStr + ' (ideal 1–3%).' } );
			} else if ( density > 0 && density < 1.0 ) {
				checks.push( { status: 'orange', message: 'Keyword density in description: ' + dStr + ' (low — aim for 1–3%).' } );
			} else if ( density > 3.0 ) {
				checks.push( { status: 'red',    message: 'Keyword density in description: ' + dStr + ' (over-optimised).' } );
			}
		}

		// ── Render ────────────────────────────────────────────────────────────
		while ( list.firstChild ) {
			list.removeChild( list.firstChild );
		}

		checks.forEach( function ( check ) {
			list.appendChild( makeCheckItem( check.status, check.message ) );
		} );
	}

	// ── Internal link suggestions ─────────────────────────────────────────────

	var suggestionsTimer = null;

	function scheduleLinkSuggestions() {
		// Debounce — don't spam the server while the user is typing.
		if ( suggestionsTimer ) {
			clearTimeout( suggestionsTimer );
		}
		suggestionsTimer = setTimeout( fetchLinkSuggestions, 500 );
	}

	function fetchLinkSuggestions() {
		var list         = byId( 'livada-seo-suggestions' );
		var keywordField = byId( 'livada_seo_focus_keyword' );

		if ( ! list || ! keywordField ) {
			return;
		}

		var keyword = keywordField.value.trim();
		if ( keyword.length < 3 ) {
			list.innerHTML = '<li class="livada-seo-suggestions__empty">Enter at least 3 characters.</li>';
			return;
		}

		var data = window.livadaSEO || {};
		var ajaxUrl = data.ajaxUrl || ( window.ajaxurl ? window.ajaxurl : '/wp-admin/admin-ajax.php' );
		var nonce   = data.adminNonce || data.nonce || '';

		// Resolve current post ID from the WP edit form.
		var postIdField = document.getElementById( 'post_ID' );
		var postId      = postIdField ? parseInt( postIdField.value, 10 ) : 0;

		var body = new URLSearchParams( {
			action:  'livada_seo_link_suggestions',
			nonce:   nonce,
			post_id: postId,
			keyword: keyword,
		} );

		list.innerHTML = '<li class="livada-seo-suggestions__empty">Loading…</li>';

		fetch( ajaxUrl, {
			method:      'POST',
			credentials: 'same-origin',
			headers:     { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
			body:        body.toString(),
		} )
			.then( function ( r ) { return r.json(); } )
			.then( function ( res ) {
				if ( ! res || ! res.success || ! res.data || ! Array.isArray( res.data.suggestions ) ) {
					list.innerHTML = '<li class="livada-seo-suggestions__empty">No suggestions found.</li>';
					return;
				}

				if ( res.data.suggestions.length === 0 ) {
					list.innerHTML = '<li class="livada-seo-suggestions__empty">No matching posts found.</li>';
					return;
				}

				while ( list.firstChild ) { list.removeChild( list.firstChild ); }

				res.data.suggestions.forEach( function ( s ) {
					var li      = document.createElement( 'li' );
					var a       = document.createElement( 'a' );
					var why     = document.createElement( 'div' );

					a.href        = s.url;
					a.target      = '_blank';
					a.rel         = 'noopener noreferrer';
					a.textContent = s.title;

					why.className   = 'why';
					why.textContent = s.why || '';

					li.appendChild( a );
					li.appendChild( why );
					list.appendChild( li );
				} );
			} )
			.catch( function () {
				list.innerHTML = '<li class="livada-seo-suggestions__empty">Could not load suggestions.</li>';
			} );
	}

	// ── Flesch reading-ease (JS port of class-analysis.php) ───────────────────

	/**
	 * Estimates syllables in a single word using the same heuristic as the PHP
	 * implementation: count vowel groups, subtract trailing silent "e", floor at 1.
	 * Handles ASCII + common Romance-language accented vowels.
	 */
	function syllables( word ) {
		word = ( word || '' ).toLowerCase().replace( /[^a-zàâäéèêëîïôöùûüÿœæáíóúñ]/gi, '' );
		if ( ! word ) { return 0; }
		var matches = word.match( /[aeiouyàâäéèêëîïôöùûüÿœæáíóúñ]+/g );
		var count   = matches ? matches.length : 0;
		// Silent "e" at the end (but not "le").
		if ( count > 1 && word.slice( -1 ) === 'e' && word.slice( -2 ) !== 'le' ) {
			count -= 1;
		}
		return Math.max( 1, count );
	}

	/**
	 * Returns a Flesch reading-ease score (0–100, higher = easier) for the
	 * given plain text. Returns 0 for empty or malformed input.
	 */
	function computeFlesch( text ) {
		text = ( text || '' ).trim();
		if ( ! text ) { return 0; }

		var words = text.split( /\s+/ ).filter( Boolean );
		var sents = text.split( /(?<=[.!?])\s+/ ).filter( Boolean );

		if ( ! words.length || ! sents.length ) { return 0; }

		var syl = 0;
		for ( var i = 0; i < words.length; i++ ) {
			syl += syllables( words[ i ] );
		}
		if ( ! syl ) { return 0; }

		var score = 206.835 - 1.015 * ( words.length / sents.length ) - 84.6 * ( syl / words.length );
		return Math.round( Math.max( 0, Math.min( 100, score ) ) );
	}

	/**
	 * Returns the keyword density (0–100) of `keyword` inside `text`. Both are
	 * lower-cased; whole-string match (substring) so multi-word keywords count
	 * as a single occurrence per appearance.
	 */
	function computeKeywordDensity( text, keyword ) {
		if ( ! text || ! keyword ) { return 0; }

		var t = text.toLowerCase();
		var k = keyword.toLowerCase();

		var totalWords = t.split( /\s+/ ).filter( Boolean ).length;
		if ( ! totalWords ) { return 0; }

		// Count keyword occurrences via a global, escaped-regex match.
		var escaped = k.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' );
		var hits    = ( t.match( new RegExp( escaped, 'g' ) ) || [] ).length;
		if ( ! hits ) { return 0; }

		return ( hits / totalWords ) * 100;
	}

	// ── OG image media picker ─────────────────────────────────────────────────

	function initOgImagePicker() {
		var pickBtn    = byId( 'livada-seo-og-pick' );
		var removeBtn  = byId( 'livada-seo-og-remove' );
		var hiddenInput = byId( 'livada_seo_og_image' );
		var preview    = byId( 'livada-seo-og-preview' );

		if ( ! pickBtn || ! hiddenInput || ! preview ) {
			return;
		}

		var mediaFrame = null;

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

			// Reuse an existing frame if already created.
			if ( mediaFrame ) {
				mediaFrame.open();
				return;
			}

			if ( ! window.wp || ! window.wp.media ) {
				// wp.media not available (shouldn't happen but guard anyway).
				return;
			}

			mediaFrame = window.wp.media( {
				title:    'Select OG Image',
				button:   { text: 'Use this image' },
				multiple: false,
				library:  { type: 'image' },
			} );

			mediaFrame.on( 'select', function () {
				var attachment = mediaFrame.state().get( 'selection' ).first().toJSON();
				var url        = attachment.url || '';

				hiddenInput.value = url;

				if ( url ) {
					preview.src = url;
					preview.classList.remove( 'is-hidden' );

					if ( removeBtn ) {
						removeBtn.classList.remove( 'is-hidden' );
					}
				}
			} );

			mediaFrame.open();
		} );

		if ( removeBtn ) {
			removeBtn.addEventListener( 'click', function ( e ) {
				e.preventDefault();
				hiddenInput.value = '';
				preview.src       = '';
				preview.classList.add( 'is-hidden' );
				removeBtn.classList.add( 'is-hidden' );
			} );
		}
	}

	// ── Schema preview (collapsible JSON-LD viewer) ───────────────────────────

	function initSchemaPreview() {
		var btn  = byId( 'livada-seo-schema-load' );
		var out  = byId( 'livada-seo-schema-output' );
		var data = window.livadaSEO || {};

		if ( ! btn || ! out ) {
			return;
		}

		btn.addEventListener( 'click', function () {
			var postIdField = document.getElementById( 'post_ID' );
			var postId      = postIdField ? parseInt( postIdField.value, 10 ) : 0;

			if ( ! postId ) {
				out.style.display = 'block';
				out.textContent   = 'Save the post once before previewing schema.';
				return;
			}

			// Build the WP REST URL — use the home URL implicit base.
			var url = ( data.restUrl || '/wp-json/' ) + 'livada-seo/v1/schema/preview/' + postId;

			btn.disabled = true;
			out.style.display = 'block';
			out.textContent   = 'Loading…';

			fetch( url, {
				credentials: 'same-origin',
				headers:     {
					'X-WP-Nonce': data.restNonce || '',
					'Accept':     'application/json',
				},
			} )
				.then( function ( r ) { return r.json().then( function ( body ) { return { ok: r.ok, body: body }; } ); } )
				.then( function ( res ) {
					btn.disabled = false;
					if ( res.ok ) {
						out.textContent = JSON.stringify( res.body, null, 2 );
					} else {
						out.textContent = ( res.body && res.body.message ) || 'Failed to load preview.';
					}
				} )
				.catch( function () {
					btn.disabled    = false;
					out.textContent = 'Network error.';
				} );
		} );
	}

	// ── Init ──────────────────────────────────────────────────────────────────

	function init() {
		initTabs();
		initCounters();
		initSerpPreview();
		initOgImagePicker();
		initSchemaPreview();
		updateLiveScore();
	}

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

}() );
