/**
 * CacheLoop Settings Page JavaScript
 *
 * Handles:
 *  - Tab navigation (with localStorage persistence)
 *  - Delay JS exclusions "restore defaults"
 *  - Import/settings-saved toast notifications
 *  - PageSpeed Speedtest (mobile + desktop) with progress bars and audit extraction
 *  - Sitemap Preloader polling
 *  - Import Settings form submission
 *
 * The "Clear Cache" button is handled by cl-admin.js (clAdminData/clShowToast),
 * not duplicated here.
 *
 * clSettingsData is injected by wp_localize_script() in CACHELOOP_Admin::cl_enqueue_assets().
 *
 * @package CacheLoop
 */

/* global clSettingsData, jQuery */
( function ( $ ) {
	'use strict';

	$( document ).ready( function () {

		// Tab Navigation
		function clSwitchTab( target ) {
			$( '.cl-nav-tab' ).removeClass( 'active' );
			$( '[data-tab="' + target + '"]' ).addClass( 'active' );
			$( '.cl-tab-pane' ).hide();
			$( '#' + target ).show();
			localStorage.setItem( 'cacheloop_active_tab', target );
		}

		$( '.cl-nav-tab' ).on( 'click', function ( e ) {
			e.preventDefault();
			clSwitchTab( $( this ).data( 'tab' ) );
		} );

		// Slim Pro reminder link — jumps to the Advanced tab
		$( '.cl-pro-strip__link' ).on( 'click', function ( e ) {
			e.preventDefault();
			clSwitchTab( $( this ).data( 'tab' ) );
		} );

		// Restore active tab
		var activeTab = localStorage.getItem( 'cacheloop_active_tab' );
		if ( activeTab && $( '#' + activeTab ).length ) {
			$( '.cl-nav-tab' ).removeClass( 'active' );
			$( '[data-tab="' + activeTab + '"]' ).addClass( 'active' );
			$( '.cl-tab-pane' ).hide();
			$( '#' + activeTab ).show();
		}

		// Restore default Delay JS exclusions
		var clDefaultExclusions = "jquery.min.js\njquery-migrate.min.js\nbootstrap.min.js\nmodernizr.custom.js\njs_composer_front.min.js\nwaypoints.min.js\nultimate.min.js\nvhparallax.min.js\nrbtools.min.js\nrs6.min.js\nslick.min.js";
		$( '#cl-restore-exclusions' ).on( 'click', function () {
			if ( confirm( clSettingsData.i18n.confirmResetExclusions ) ) {
				$( '#cl-delay-js-exclusions' ).val( clDefaultExclusions );
			}
		} );

		// Show success toast on import (if any)
		var urlParams = new URLSearchParams( window.location.search );
		if ( urlParams.has( 'cl_imported' ) || urlParams.has( 'cl_fs_reset' ) || urlParams.has( 'settings-updated' ) ) {
			var $toast = $( '#cl-toast' );
			var msg = urlParams.has( 'cl_imported' )
				? clSettingsData.i18n.importedMsg
				: ( urlParams.has( 'cl_fs_reset' )
					? clSettingsData.i18n.fsResetMsg
					: clSettingsData.i18n.savedMsg );
			$toast.removeClass( 'cl-toast--error' ).text( msg );
			$toast.addClass( 'cl-toast--visible' );
			setTimeout( function () {
				$toast.removeClass( 'cl-toast--visible' );
			}, 3000 );

			// Clean up the URL
			var newUrl = window.location.protocol + '//' + window.location.host + window.location.pathname + '?page=' + urlParams.get( 'page' );
			window.history.replaceState( { path: newUrl }, '', newUrl );
		}

		// Speedtest Tabs Switcher
		$( '.cl-ps-tab' ).on( 'click', function () {
			$( '.cl-ps-tab' ).removeClass( 'active' );
			$( this ).addClass( 'active' );
			$( '.cl-ps-panel' ).hide();
			$( '#cl-ps-panel-' + $( this ).data( 'tab' ) ).show();
		} );

		// Speedtest API call with Progress Bar (Mobile then Desktop)
		$( '#cl-run-pagespeed' ).on( 'click', function ( e ) {
			e.preventDefault();
			var $btn = $( this );
			var $spinner = $( '#cl-pagespeed-spinner' );
			var $progressCont = $( '#cl-pagespeed-progress-container' );
			var $progressBar = $( '#cl-pagespeed-progress-bar' );
			var $progressText = $( '#cl-pagespeed-progress-text' );
			var $progressLabel = $( '#cl-pagespeed-progress-label' );
			var apiKey = $( 'input[name="cacheloop_settings[pagespeed_api_key]"]' ).val() || '';

			$btn.prop( 'disabled', true );
			$spinner.show();

			// Setup Progress Bar for Mobile (0% to 50%)
			$progressCont.slideDown( 200 );
			$progressBar.css( 'width', '0%' );
			$progressText.text( '0%' );
			$progressLabel.text( clSettingsData.i18n.analyzingMobile );

			var progress = 0;
			var stepTime = 100;

			// Mobile Animation
			var mobileInterval = setInterval( function () {
				if ( progress < 45 ) {
					progress += ( 45 / 120 ); // Reach 45% in ~12s
					var val = Math.min( Math.round( progress ), 45 );
					$progressBar.css( 'width', val + '%' );
					$progressText.text( val + '%' );
				}
			}, stepTime );

			// 1. Run Mobile
			$.post( ajaxurl, {
				action: 'cacheloop_run_pagespeed',
				nonce: clSettingsData.nonce,
				api_key: apiKey,
				strategy: 'mobile'
			}, function ( responseM ) {
				clearInterval( mobileInterval );
				if ( ! responseM.success ) {
					throw_speedtest_error( responseM.data.message || 'Errore Mobile.' );
					return;
				}

				$progressBar.css( 'width', '50%' );
				$progressText.text( '50%' );
				$progressLabel.text( clSettingsData.i18n.analyzingDesktop );

				var lrM = responseM.data.lighthouseResult;
				if ( ! lrM ) {
					throw_speedtest_error( 'Nessun risultato Lighthouse Mobile.' );
					return;
				}

				var scoreM = Math.round( lrM.categories.performance.score * 100 );
				var fcpM = lrM.audits['first-contentful-paint'].displayValue;
				var lcpM = lrM.audits['largest-contentful-paint'].displayValue;
				var tbtM = lrM.audits['total-blocking-time'].displayValue;
				var clsM = lrM.audits['cumulative-layout-shift'].displayValue;

				// Pull a one-line "what exactly" out of an audit's details: the real
				// filename/entity and its real number, instead of just the headline
				// displayValue. Different audit shapes need different extraction:
				// - document-latency-insight: checklist + debugData.serverResponseTime
				// - lcp-breakdown-insight: list wrapping a subpart-duration table
				// - lcp-discovery-insight: list wrapping a checklist + the LCP node
				// - everything else (render-blocking, cache, images, third-party,
				//   unused code, JS execution time...): plain table of items
				function clExtractAuditDetail( a ) {
					try {
						var d = a.details;
						if ( ! d ) { return ''; }
						if ( d.type === 'checklist' && d.debugData ) {
							var parts = [];
							if ( typeof d.debugData.serverResponseTime !== 'undefined' ) {
								parts.push( 'TTFB ' + Math.round( d.debugData.serverResponseTime ) + 'ms' );
							}
							Object.keys( d.items || {} ).forEach( function ( k ) {
								var chk = d.items[ k ];
								if ( chk && chk.value === false ) { parts.push( 'FAIL: ' + chk.label ); }
							} );
							return parts.join( ' | ' );
						}
						// lcp-breakdown-insight only: a list wrapping a subpart-duration
						// table with {label, duration} rows. Other insights (e.g.
						// forced-reflow-insight) also wrap a table in a list but with a
						// different row shape — id-gate this so it doesn't misfire there.
						if ( a.id === 'lcp-breakdown-insight' && d.type === 'list' && d.items && d.items[0] && d.items[0].type === 'table' ) {
							var sub = d.items[0].items || [];
							if ( sub.length ) {
								var worst = sub[0];
								sub.forEach( function ( row ) {
									if ( typeof row.duration === 'number' && typeof worst.duration === 'number' && row.duration > worst.duration ) { worst = row; }
								} );
								if ( typeof worst.label === 'string' && typeof worst.duration === 'number' ) {
									return 'Biggest delay: ' + worst.label + ' (' + Math.round( worst.duration ) + 'ms)';
								}
							}
							return '';
						}
						if ( d.type === 'list' && d.items && d.items[0] && d.items[0].type === 'checklist' ) {
							var fails = [];
							var chkItems = d.items[0].items || {};
							Object.keys( chkItems ).forEach( function ( k ) {
								if ( chkItems[ k ] && chkItems[ k ].value === false ) { fails.push( chkItems[ k ].label ); }
							} );
							return fails.join( ' | ' );
						}
						if ( d.type === 'table' && Array.isArray( d.items ) && d.items.length ) {
							var item = d.items[0];
							var name = item.entity || ( item.url ? item.url.split( '/' ).pop().split( '?' )[0] : '' ) || ( item.node && item.node.nodeLabel ) || '';
							var metric = '';
							if ( typeof item.wastedMs !== 'undefined' ) { metric = Math.round( item.wastedMs ) + 'ms'; } else if ( typeof item.mainThreadTime !== 'undefined' ) { metric = Math.round( item.mainThreadTime ) + 'ms'; } else if ( typeof item.total !== 'undefined' ) { metric = Math.round( item.total ) + 'ms'; } else if ( typeof item.wastedBytes !== 'undefined' ) { metric = Math.round( item.wastedBytes / 1024 ) + 'KiB'; } else if ( typeof item.cacheLifetimeMs !== 'undefined' ) { metric = 'TTL ' + Math.round( item.cacheLifetimeMs / 1000 ) + 's'; } else if ( item.protocol ) { metric = item.protocol; }
							return name ? ( name + ( metric ? ' (' + metric + ')' : '' ) ) : '';
						}
					} catch ( e ) { /* fall through to empty */ }
					return '';
				}

				// The LCP element itself: pull whatever src/selector Google's node
				// snapshot gives us, so the panel can point at the actual hero image
				// instead of asking the user to guess its URL.
				function clExtractHeroImageHint( a ) {
					try {
						var d = a.details;
						if ( ! d || d.type !== 'list' ) { return ''; }
						var nodeItem = null;
						d.items.forEach( function ( it ) { if ( it.type === 'node' ) { nodeItem = it; } } );
						if ( ! nodeItem ) { return ''; }
						var src = '';
						var m = /src="([^"]*)"/.exec( nodeItem.snippet || '' );
						if ( m ) { src = m[1]; }
						return JSON.stringify( {
							src: src,
							truncated: src.indexOf( '…' ) !== -1 || src.indexOf( '...' ) !== -1,
							selector: nodeItem.selector || '',
							label: nodeItem.nodeLabel || ''
						} );
					} catch ( e ) { return ''; }
				}

				// Capture the actual failing diagnostics/insights Google reported,
				// so the Pro Analysis panel can quote Google's own findings with real
				// numbers. Lighthouse groups these under 'diagnostics' and 'insights'
				// (the old 'load-opportunities' group was retired).
				var auditsM = [];
				var heroImageHintM = '';
				try {
					var refsM = ( lrM.categories.performance.auditRefs || [] );
					refsM.forEach( function ( ref ) {
						if ( ref.group !== 'diagnostics' && ref.group !== 'insights' ) {
							return;
						}
						var a = lrM.audits[ ref.id ];
						if ( ! a || a.score === null || a.score >= 0.9 ) {
							return;
						}
						auditsM.push( {
							id: ref.id,
							title: a.title,
							displayValue: a.displayValue || '',
							savingsMs: ( a.details && a.details.overallSavingsMs ) ? Math.round( a.details.overallSavingsMs ) : 0,
							detail: clExtractAuditDetail( a )
						} );
						if ( ref.id === 'lcp-discovery-insight' ) {
							heroImageHintM = clExtractHeroImageHint( a );
						}
					} );
					auditsM.sort( function ( a, b ) { return b.savingsMs - a.savingsMs; } );
					auditsM = auditsM.slice( 0, 8 );
				} catch ( err ) {
					auditsM = [];
				}

				// Save Mobile Results
				$.post( ajaxurl, {
					action: 'cacheloop_save_pagespeed',
					nonce: clSettingsData.nonce,
					strategy: 'mobile',
					score: scoreM,
					fcp: fcpM,
					lcp: lcpM,
					tbt: tbtM,
					cls: clsM,
					audits: JSON.stringify( auditsM ),
					hero_image_hint: heroImageHintM
				}, function () {

					// Desktop Animation (50% to 95%)
					var desktopInterval = setInterval( function () {
						if ( progress < 95 ) {
							progress += ( 45 / 120 );
							var val = Math.min( Math.round( progress ), 95 );
							$progressBar.css( 'width', val + '%' );
							$progressText.text( val + '%' );
						}
					}, stepTime );

					// 2. Run Desktop
					$.post( ajaxurl, {
						action: 'cacheloop_run_pagespeed',
						nonce: clSettingsData.nonce,
						api_key: apiKey,
						strategy: 'desktop'
					}, function ( responseD ) {
						clearInterval( desktopInterval );
						if ( ! responseD.success ) {
							throw_speedtest_error( responseD.data.message || 'Errore Desktop.' );
							return;
						}

						$progressBar.css( 'width', '100%' );
						$progressText.text( '100%' );

						var lrD = responseD.data.lighthouseResult;
						if ( ! lrD ) {
							throw_speedtest_error( 'Nessun risultato Lighthouse Desktop.' );
							return;
						}

						var scoreD = Math.round( lrD.categories.performance.score * 100 );
						var fcpD = lrD.audits['first-contentful-paint'].displayValue;
						var lcpD = lrD.audits['largest-contentful-paint'].displayValue;
						var tbtD = lrD.audits['total-blocking-time'].displayValue;
						var clsD = lrD.audits['cumulative-layout-shift'].displayValue;

						// Save Desktop Results
						$.post( ajaxurl, {
							action: 'cacheloop_save_pagespeed',
							nonce: clSettingsData.nonce,
							strategy: 'desktop',
							score: scoreD,
							fcp: fcpD,
							lcp: lcpD,
							tbt: tbtD,
							cls: clsD
						}, function () {
							setTimeout( function () { window.location.reload(); }, 500 );
						} );

					} ).fail( function () {
						clearInterval( desktopInterval );
						throw_speedtest_error( 'Errore di connessione Desktop.' );
					} );
				} );

			} ).fail( function () {
				clearInterval( mobileInterval );
				throw_speedtest_error( 'Errore di connessione Mobile.' );
			} );

		} );

		// Apply Google's Suggestions: check the CSS/JS files flagged by the last
		// Speedtest run. Just ticks the boxes — user still hits Save Settings.
		$( '#cl-apply-google-suggestions' ).on( 'click', function () {
			$( '.cl-flagged-checkbox' ).prop( 'checked', true );
			var $toast = $( '#cl-toast' );
			$toast.removeClass( 'cl-toast--error' ).text( clSettingsData.i18n.suggestionsApplied );
			$toast.addClass( 'cl-toast--visible' );
			setTimeout( function () { $toast.removeClass( 'cl-toast--visible' ); }, 4000 );
		} );

		// Helper: show speedtest error in toast
		function throw_speedtest_error( msg ) {
			$( '#cl-pagespeed-progress-container' ).slideUp( 200 );
			$( '#cl-run-pagespeed' ).prop( 'disabled', false );
			$( '#cl-pagespeed-spinner' ).hide();
			var $toast = $( '#cl-toast' );
			$toast.addClass( 'cl-toast--error' ).text( msg );
			$toast.addClass( 'cl-toast--visible' );
			setTimeout( function () { $toast.removeClass( 'cl-toast--visible cl-toast--error' ); }, 6000 );
		}

		// ==========================================
		// Sitemap Preloader Polling Logic
		// ==========================================
		var $preloadBtn = $( '#cl-start-preload-btn' );
		var $preloadSpinner = $( '#cl-preload-spinner' );
		var $preloadCont = $( '#cl-preload-progress-container' );
		var $preloadBar = $( '#cl-preload-progress-bar' );
		var $preloadText = $( '#cl-preload-progress-text' );
		var $preloadPercent = $( '#cl-preload-progress-percent' );
		var preloadInterval = null;

		function checkPreloadStatus() {
			$.post( ajaxurl, {
				action: 'cacheloop_get_preload_status',
				nonce: clSettingsData.nonce
			}, function ( response ) {
				if ( response.success && response.data.running ) {
					// Update UI
					$preloadBtn.prop( 'disabled', true );
					$preloadSpinner.show();
					$preloadCont.slideDown( 200 );

					var comp = response.data.completed;
					var tot = response.data.total;
					var perc = response.data.percent;

					$preloadText.text( comp + ' / ' + tot + ' URLs' );
					$preloadPercent.text( perc + '%' );
					$preloadBar.css( 'width', perc + '%' );

					if ( perc >= 100 ) {
						clearInterval( preloadInterval );
						setTimeout( function () {
							$preloadCont.slideUp();
							$preloadBtn.prop( 'disabled', false );
							$preloadSpinner.hide();
						}, 2000 );
					}
				} else {
					// Not running
					clearInterval( preloadInterval );
					$preloadCont.slideUp();
					$preloadBtn.prop( 'disabled', false );
					$preloadSpinner.hide();
				}
			} );
		}

		// Start Preload Scan
		$preloadBtn.on( 'click', function ( e ) {
			e.preventDefault();
			$preloadBtn.prop( 'disabled', true );
			$preloadSpinner.show();

			$.post( ajaxurl, {
				action: 'cacheloop_start_preload',
				nonce: clSettingsData.nonce
			}, function ( response ) {
				if ( response.success ) {
					$preloadCont.slideDown( 200 );
					$preloadText.text( '0 / ' + response.data.total + ' URLs' );
					$preloadPercent.text( '0%' );
					$preloadBar.css( 'width', '0%' );

					// Start polling every 5 seconds
					if ( preloadInterval ) { clearInterval( preloadInterval ); }
					preloadInterval = setInterval( checkPreloadStatus, 5000 );
				} else {
					$preloadBtn.prop( 'disabled', false );
					$preloadSpinner.hide();
					alert( response.data.message || 'Error starting preload.' );
				}
			} ).fail( function () {
				$preloadBtn.prop( 'disabled', false );
				$preloadSpinner.hide();
				alert( 'Connection error.' );
			} );
		} );

		// Initial check on load
		if ( $preloadBtn.length ) {
			checkPreloadStatus();
			// Start polling if running
			preloadInterval = setInterval( checkPreloadStatus, 5000 );
		}

		// ==========================================
		// Fix for Nested Form Issue (Import Settings)
		// ==========================================
		$( '#cl-import-trigger-btn' ).on( 'click', function ( e ) {
			e.preventDefault();
			var fileInput = $( '#cl_import_file_dummy' )[0];
			if ( ! fileInput.files.length ) {
				alert( clSettingsData.i18n.selectJsonFile );
				return;
			}

			// Create a hidden form dynamically to submit the file securely without nesting forms
			var $form = $( '<form>', {
				action: clSettingsData.adminPostUrl,
				method: 'POST',
				enctype: 'multipart/form-data'
			} ).css( 'display', 'none' ).appendTo( 'body' );

			$( '<input>' ).attr( { type: 'hidden', name: 'action', value: 'cacheloop_import_settings' } ).appendTo( $form );
			$( '<input>' ).attr( { type: 'hidden', name: '_wpnonce', value: $( '#cl_import_nonce' ).val() } ).appendTo( $form );

			// Move file input to the new form to preserve the selected file
			$( fileInput ).detach().attr( 'name', 'cl_import_file' ).appendTo( $form );

			$form.submit();
		} );

	} );
}( jQuery ) );
