import '../scss/admin.scss';

/**
 * Monitor.Cat — Shared admin utilities.
 *
 * Provides the MonitorCatAdmin namespace with common helpers used
 * across all admin pages. Relies on the MonitorCat global object
 * set via wp_localize_script.
 *
 * @package MonitorCat
 */
( function () {
	'use strict';

	var config = window.MonitorCat || {};

	/**
	 * Wrapper around fetch() that adds the WP REST nonce header
	 * and builds the full URL from a relative endpoint.
	 *
	 * @param {string} endpoint REST endpoint path (e.g. '/seo/scan').
	 * @param {Object} options  Fetch options (method, body, etc.).
	 * @return {Promise<Object>} Parsed JSON response.
	 */
	function apiFetch( endpoint, options ) {
		var base = ( config.restBase || config.restUrl || '/wp-json/monitor-cat/v1/' ).replace( /\/+$/, '' );
		var url = base + endpoint;

		var defaults = {
			method: 'GET',
			headers: {
				'Content-Type': 'application/json',
				'X-WP-Nonce': config.nonce || '',
			},
			credentials: 'same-origin',
		};

		var merged = Object.assign( {}, defaults, options || {} );
		merged.headers = Object.assign( {}, defaults.headers, ( options && options.headers ) || {} );

		return fetch( url, merged ).then( function ( response ) {
			if ( ! response.ok ) {
				return response.json().then( function ( err ) {
					throw new Error( err.message || 'Request failed' );
				} );
			}
			return response.json();
		} );
	}

	/**
	 * Display a toast notification.
	 *
	 * @param {string} message  Notification text.
	 * @param {string} type     One of 'success', 'error', 'warning', 'info'.
	 * @param {number} duration Auto-dismiss in milliseconds (default 4000).
	 */
	function notify( message, type, duration ) {
		type = type || 'info';
		duration = duration || 4000;

		var container = document.getElementById( 'mc-toast-container' );
		if ( ! container ) {
			container = document.createElement( 'div' );
			container.id = 'mc-toast-container';
			container.className = 'mc-toast-container';
			document.body.appendChild( container );
		}

		var toast = document.createElement( 'div' );
		toast.className = 'mc-toast mc-toast-' + type;
		toast.setAttribute( 'role', 'status' );
		toast.setAttribute( 'aria-live', 'polite' );
		toast.textContent = message;

		container.appendChild( toast );

		// Trigger enter animation.
		requestAnimationFrame( function () {
			toast.classList.add( 'mc-toast-visible' );
		} );

		setTimeout( function () {
			toast.classList.remove( 'mc-toast-visible' );
			toast.addEventListener( 'transitionend', function () {
				if ( toast.parentNode ) {
					toast.parentNode.removeChild( toast );
				}
			} );
		}, duration );
	}

	/**
	 * Initialise tab switching inside a container.
	 *
	 * Tabs use data-tab-target to reference panels with data-tab-panel.
	 *
	 * @param {Element} container Parent element containing tabs and panels.
	 */
	function initTabs( container ) {
		if ( ! container ) {
			return;
		}

		var tabs = container.querySelectorAll( '[data-tab-target]' );
		var panels = container.querySelectorAll( '[data-tab-panel]' );

		tabs.forEach( function ( tab ) {
			tab.addEventListener( 'click', function ( e ) {
				e.preventDefault();
				var target = tab.getAttribute( 'data-tab-target' );

				tabs.forEach( function ( t ) {
					t.classList.toggle( 'is-active', t === tab );
				} );

				panels.forEach( function ( p ) {
					p.classList.toggle( 'is-active', p.getAttribute( 'data-tab-panel' ) === target );
				} );
			} );
		} );
	}

	/**
	 * Initialise IntersectionObserver-based reveal animations.
	 *
	 * Elements with the class .mc-reveal will receive .mc-revealed
	 * when they scroll into view.
	 */
	function initReveal() {
		if ( ! ( 'IntersectionObserver' in window ) ) {
			return;
		}

		var observer = new IntersectionObserver(
			function ( entries ) {
				entries.forEach( function ( entry ) {
					if ( entry.isIntersecting ) {
						entry.target.classList.add( 'mc-revealed' );
						observer.unobserve( entry.target );
					}
				} );
			},
			{ threshold: 0.1 }
		);

		document.querySelectorAll( '.mc-reveal' ).forEach( function ( el ) {
			observer.observe( el );
		} );
	}

	// -------------------------------------------------------------------------
	// Custom dropdown — enhances native <select> elements
	// -------------------------------------------------------------------------

	/**
	 * Enhance a native <select> into a styled custom dropdown.
	 *
	 * Wraps the select in a .mc-dropdown container with a trigger button
	 * and a floating option list. The native select stays in the DOM
	 * (hidden) so form values and change events work normally.
	 *
	 * @param {HTMLSelectElement} select  The native select element.
	 * @param {Object}           opts    Options: { size: 'sm' }.
	 * @return {Object} API: { refresh(), destroy() }.
	 */
	function enhanceSelect( select, opts ) {
		if ( ! select || select.dataset.mcEnhanced ) {
			return null;
		}
		opts = opts || {};
		select.dataset.mcEnhanced = '1';

		// Build wrapper.
		var wrapper = document.createElement( 'div' );
		wrapper.className = 'mc-dropdown';
		select.parentNode.insertBefore( wrapper, select );
		wrapper.appendChild( select );

		// Build trigger.
		var trigger = document.createElement( 'button' );
		trigger.type = 'button';
		trigger.className = 'mc-dropdown-trigger';
		if ( opts.size === 'sm' ) {
			trigger.classList.add( 'mc-dropdown-trigger-sm' );
		}
		trigger.setAttribute( 'role', 'combobox' );
		trigger.setAttribute( 'aria-haspopup', 'listbox' );
		trigger.setAttribute( 'aria-expanded', 'false' );
		if ( select.getAttribute( 'aria-label' ) ) {
			trigger.setAttribute( 'aria-label', select.getAttribute( 'aria-label' ) );
		}
		wrapper.appendChild( trigger );

		// Build list.
		var list = document.createElement( 'div' );
		list.className = 'mc-dropdown-list';
		list.setAttribute( 'role', 'listbox' );
		wrapper.appendChild( list );

		var focusedIndex = -1;

		function getLabel( option ) {
			return option.textContent || option.label || '';
		}

		function buildOptions() {
			// Clear existing options safely.
			while ( list.firstChild ) {
				list.removeChild( list.firstChild );
			}
			focusedIndex = -1;
			var options = select.options;
			for ( var i = 0; i < options.length; i++ ) {
				var btn = document.createElement( 'button' );
				btn.type = 'button';
				btn.className = 'mc-dropdown-option';
				btn.setAttribute( 'role', 'option' );
				btn.dataset.value = options[ i ].value;
				btn.dataset.index = String( i );
				btn.textContent = getLabel( options[ i ] );
				if ( i === select.selectedIndex ) {
					btn.classList.add( 'is-selected' );
					btn.setAttribute( 'aria-selected', 'true' );
				}
				list.appendChild( btn );
			}
			updateTriggerText();
		}

		function updateTriggerText() {
			var sel = select.options[ select.selectedIndex ];
			trigger.textContent = sel ? getLabel( sel ) : '';
		}

		function open() {
			wrapper.classList.add( 'is-open' );
			trigger.setAttribute( 'aria-expanded', 'true' );
			// Scroll selected into view.
			var selected = list.querySelector( '.is-selected' );
			if ( selected ) {
				selected.scrollIntoView( { block: 'nearest' } );
			}
		}

		function close() {
			wrapper.classList.remove( 'is-open' );
			trigger.setAttribute( 'aria-expanded', 'false' );
			clearFocus();
		}

		function isOpen() {
			return wrapper.classList.contains( 'is-open' );
		}

		function selectByIndex( idx ) {
			if ( idx < 0 || idx >= select.options.length ) {
				return;
			}
			select.selectedIndex = idx;
			// Update visual state.
			var btns = list.querySelectorAll( '.mc-dropdown-option' );
			btns.forEach( function ( b, i ) {
				b.classList.toggle( 'is-selected', i === idx );
				b.setAttribute( 'aria-selected', i === idx ? 'true' : 'false' );
			} );
			updateTriggerText();
			// Fire native change event.
			var evt = new Event( 'change', { bubbles: true } );
			select.dispatchEvent( evt );
		}

		function clearFocus() {
			focusedIndex = -1;
			list.querySelectorAll( '.mc-dropdown-option' ).forEach( function ( b ) {
				b.classList.remove( 'is-focused' );
			} );
		}

		function setFocus( idx ) {
			var btns = list.querySelectorAll( '.mc-dropdown-option' );
			if ( idx < 0 ) { idx = btns.length - 1; }
			if ( idx >= btns.length ) { idx = 0; }
			clearFocus();
			focusedIndex = idx;
			btns[ idx ].classList.add( 'is-focused' );
			btns[ idx ].scrollIntoView( { block: 'nearest' } );
		}

		// Event: trigger click.
		trigger.addEventListener( 'click', function ( e ) {
			e.stopPropagation();
			if ( isOpen() ) {
				close();
			} else {
				open();
			}
		} );

		// Event: option click.
		list.addEventListener( 'click', function ( e ) {
			var btn = e.target.closest( '.mc-dropdown-option' );
			if ( btn ) {
				selectByIndex( parseInt( btn.dataset.index, 10 ) );
				close();
				trigger.focus();
			}
		} );

		// Event: keyboard navigation.
		trigger.addEventListener( 'keydown', function ( e ) {
			var key = e.key;
			if ( key === 'ArrowDown' || key === 'Down' ) {
				e.preventDefault();
				if ( ! isOpen() ) {
					open();
				}
				setFocus( focusedIndex + 1 );
			} else if ( key === 'ArrowUp' || key === 'Up' ) {
				e.preventDefault();
				if ( ! isOpen() ) {
					open();
				}
				setFocus( focusedIndex - 1 );
			} else if ( key === 'Enter' || key === ' ' ) {
				e.preventDefault();
				if ( isOpen() && focusedIndex >= 0 ) {
					selectByIndex( focusedIndex );
					close();
				} else {
					open();
				}
			} else if ( key === 'Escape' || key === 'Esc' ) {
				close();
			} else if ( key === 'Tab' ) {
				close();
			}
		} );

		// Event: click outside.
		document.addEventListener( 'click', function ( e ) {
			if ( isOpen() && ! wrapper.contains( e.target ) ) {
				close();
			}
		} );

		// Watch for programmatic option changes via MutationObserver.
		var observer = new MutationObserver( function () {
			buildOptions();
		} );
		observer.observe( select, { childList: true, subtree: true } );

		// Initial build.
		buildOptions();

		// Public API.
		var dropdownApi = {
			refresh: buildOptions,
			destroy: function () {
				observer.disconnect();
				wrapper.parentNode.insertBefore( select, wrapper );
				wrapper.parentNode.removeChild( wrapper );
				delete select.dataset.mcEnhanced;
			},
		};

		select._mcDropdown = dropdownApi;
		return dropdownApi;
	}

	// -------------------------------------------------------------------------
	// Auto-init on DOMContentLoaded
	// -------------------------------------------------------------------------
	document.addEventListener( 'DOMContentLoaded', function () {
		// Init tabs on any container that opts in.
		document.querySelectorAll( '[data-mc-tabs]' ).forEach( function ( container ) {
			initTabs( container );
		} );

		// Init reveal animations.
		initReveal();
	} );

	// -------------------------------------------------------------------------
	// Public API
	// -------------------------------------------------------------------------
	window.MonitorCatAdmin = {
		apiFetch: apiFetch,
		notify: notify,
		initTabs: initTabs,
		initReveal: initReveal,
		enhanceSelect: enhanceSelect,
	};
} )();
