Current File : //home/abedqjib/krishanfoundation.com/wp-content/plugins/surerank/src/apps/divi/index.js
import {
	cn,
	getStatusIndicatorClasses,
	getStatusIndicatorAriaLabel,
} from '@/functions/utils';
import { STORE_NAME } from '@/store/constants';
import { select } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { getTooltipText } from '@/apps/seo-popup/utils/page-checks-status-tooltip-text';
import './tooltip.css';
import {
	handleOpenSureRankDrawer,
	sureRankLogoForBuilder,
} from '@SeoPopup/utils/page-builder-functions';
import { ENABLE_PAGE_LEVEL_SEO } from '@/global/constants';
import {
	getPageCheckStatus,
	handleRefreshWithBrokenLinks,
} from '../elementor/page-checks';

const DIVI_TARGET_SELECTOR = '.et-vb-page-bar-tools-action-buttons';

// Divi-style tooltip implementation — dark rounded pill, no arrow
const createSureRankTooltip = ( targetElement, tooltipText ) => {
	if ( ! targetElement || ! tooltipText ) {
		return;
	}

	// Create wrapper with surerank-root class
	const wrapper = document.createElement( 'div' );
	wrapper.className = 'surerank-root';

	// Create tooltip element matching Divi's native tooltip style
	const tooltip = document.createElement( 'div' );
	tooltip.className = cn(
		'surerank-tooltip',
		'absolute',
		'bg-black/95',
		'text-white',
		'px-3',
		'py-[0.3125rem]',
		'rounded',
		'text-xs',
		'font-normal',
		'leading-normal',
		'whitespace-nowrap',
		'invisible',
		'opacity-0',
		'pointer-events-none',
		'z-[9999]',
		'top-0',
		'left-0'
	);
	tooltip.textContent = tooltipText;

	// Append tooltip to wrapper
	wrapper.appendChild( tooltip );

	// Append wrapper to body
	document.body.appendChild( wrapper );

	// Position tooltip function
	const positionTooltip = () => {
		const targetRect = targetElement.getBoundingClientRect();

		// Position below the target element with small gap
		const top = targetRect.bottom + 10;
		const centerX = targetRect.left + targetRect.width / 2;

		tooltip.style.top = top + 'px';
		tooltip.style.left = centerX + 'px';
	};

	// Show tooltip
	const showTooltip = () => {
		positionTooltip();
		tooltip.classList.remove( 'invisible' );
		tooltip.classList.add( 'visible', 'opacity-100' );
	};

	// Hide tooltip
	const hideTooltip = () => {
		tooltip.classList.remove( 'visible', 'opacity-100' );
		tooltip.classList.add( 'invisible', 'opacity-0' );
	};

	const handleMouseEnter = () => {
		showTooltip();
	};

	const handleMouseLeave = () => {
		hideTooltip();
	};

	// Attach event listeners
	targetElement.addEventListener( 'mouseenter', handleMouseEnter );
	targetElement.addEventListener( 'mouseleave', handleMouseLeave );
	targetElement.addEventListener( 'focus', showTooltip );
	targetElement.addEventListener( 'blur', hideTooltip );

	// Return cleanup function
	return () => {
		targetElement.removeEventListener( 'mouseenter', handleMouseEnter );
		targetElement.removeEventListener( 'mouseleave', handleMouseLeave );
		targetElement.removeEventListener( 'focus', showTooltip );
		targetElement.removeEventListener( 'blur', hideTooltip );
		if ( wrapper.parentNode ) {
			wrapper.parentNode.removeChild( wrapper );
		}
	};
};

// Function to create status indicator element
const createStatusIndicator = () => {
	const { status, counts } = getPageCheckStatus();

	// Don't show indicator if no status
	if ( ! status || ! ENABLE_PAGE_LEVEL_SEO ) {
		return null;
	}

	// Status indicator colors based on check status
	const statusClasses = getStatusIndicatorClasses( status );

	// Accessibility label for the indicator
	const ariaLabel = getStatusIndicatorAriaLabel( counts.errorAndWarnings );

	const indicator = document.createElement( 'div' );
	indicator.className = cn(
		'surerank-status-indicator',
		'absolute top-0.5 right-0.5 size-2 rounded-full z-10 duration-200',
		statusClasses
	);
	indicator.setAttribute( 'aria-label', ariaLabel );
	indicator.setAttribute( 'title', ariaLabel );

	return indicator;
};

// Main setup function — called after store is initialized
const setupDiviIntegration = () => {
	let tooltipCleanup = null;
	let unsubscribe = null;
	let observer = null;

	const inject = () => {
		const container = document.querySelector( DIVI_TARGET_SELECTOR );
		if ( ! container ) {
			return;
		}

		// Already injected into this container instance — no-op.
		if ( container.querySelector( '.surerank-divi-btn-wrapper' ) ) {
			return;
		}

		// Container was replaced by a Divi re-render — clean up previous injection.
		if ( tooltipCleanup ) {
			tooltipCleanup();
			tooltipCleanup = null;
		}
		if ( unsubscribe ) {
			unsubscribe();
			unsubscribe = null;
		}

		// Create surerank-root wrapper for TailwindCSS
		const sureRankWrapper = document.createElement( 'div' );
		sureRankWrapper.className = 'surerank-root surerank-divi-btn-wrapper';

		// Create the button matching Divi's own button class
		const btn = document.createElement( 'button' );
		btn.className = 'et-vb-page-bar-button';
		btn.type = 'button';
		btn.setAttribute( 'aria-label', __( 'Open SureRank SEO', 'surerank' ) );
		btn.tabIndex = 0;

		// Wrapper with relative positioning for the status indicator
		const wrap = document.createElement( 'div' );
		wrap.className = 'relative';
		wrap.style.cssText =
			'width:28px;min-width:28px;height:28px;display:flex;align-items:center;justify-content:center;';
		wrap.innerHTML = sureRankLogoForBuilder( 'w-5 h-5' );

		btn.appendChild( wrap );
		btn.addEventListener( 'click', ( e ) => {
			e.preventDefault();
			e.stopPropagation();
			handleOpenSureRankDrawer();
		} );

		sureRankWrapper.appendChild( btn );
		container.appendChild( sureRankWrapper );

		// Function to update the status indicator
		const updateStatusIndicator = () => {
			const existing = wrap.querySelector( '.surerank-status-indicator' );
			if ( existing ) {
				existing.remove();
			}

			const indicator = createStatusIndicator();
			if ( indicator ) {
				wrap.appendChild( indicator );
			}
		};

		// Function to update the tooltip
		const updateTooltip = () => {
			if ( tooltipCleanup ) {
				tooltipCleanup();
			}
			const { counts } = getPageCheckStatus();
			tooltipCleanup = createSureRankTooltip(
				btn,
				getTooltipText( counts )
			);
		};

		// Initial status indicator update
		updateStatusIndicator();

		// Refresh page checks on page load if not already called
		handleRefreshWithBrokenLinks();

		// Subscribe to store changes to update the status and tooltip.
		unsubscribe = wp?.data?.subscribe?.( () => {
			updateStatusIndicator();
			updateTooltip();
		} );

		// Add tooltip to the button and store cleanup function
		const { counts } = getPageCheckStatus();
		tooltipCleanup = createSureRankTooltip( btn, getTooltipText( counts ) );
	};

	// Try injecting immediately
	inject();

	// Keep watching — Divi re-renders its page bar during new-page initialisation,
	// which removes any previously injected button. The DOM-presence check in
	// inject() makes each callback a fast no-op when the button is already there.
	observer = new MutationObserver( inject );
	observer.observe( document.body, {
		childList: true,
		subtree: true,
	} );

	// Cleanup on page unload
	window.addEventListener( 'beforeunload', () => {
		if ( tooltipCleanup ) {
			tooltipCleanup();
			tooltipCleanup = null;
		}
		if ( unsubscribe && typeof unsubscribe === 'function' ) {
			unsubscribe();
			unsubscribe = null;
		}
		if ( observer ) {
			observer.disconnect();
			observer = null;
		}
	} );
};

// Wait for store initialization before setting up Divi integration
const waitForStoreInit = () => {
	let retryCount = 0;
	let storeUnsubscribe = null;
	let isInitialized = false;
	const maxRetries = 50; // Maximum 5 seconds of retrying (50 * 100ms)

	const cleanup = () => {
		if ( storeUnsubscribe && typeof storeUnsubscribe === 'function' ) {
			storeUnsubscribe();
			storeUnsubscribe = null;
		}
	};

	const checkStoreAndInitialize = () => {
		// Prevent multiple initializations
		if ( isInitialized ) {
			return;
		}

		try {
			const storeSelectors = select( STORE_NAME );

			// Check if store exists and has the required functions
			if (
				! storeSelectors ||
				typeof storeSelectors.getVariables !== 'function'
			) {
				// Store not available yet, retry with limit
				if ( retryCount < maxRetries ) {
					retryCount++;
					setTimeout( checkStoreAndInitialize, 100 );
				}
				return;
			}

			const variables = storeSelectors.getVariables();

			if ( variables ) {
				// Store is initialized, proceed with setup
				isInitialized = true;
				cleanup();
				setupDiviIntegration();
			} else if ( ! storeUnsubscribe ) {
				// Store exists but not initialized, subscribe once
				storeUnsubscribe = wp?.data?.subscribe?.( () => {
					try {
						const currentVariables =
							select( STORE_NAME )?.getVariables();
						if ( currentVariables && ! isInitialized ) {
							isInitialized = true;
							cleanup();
							setupDiviIntegration();
						}
					} catch ( error ) {
						// Silently handle subscription errors
					}
				} );

				// Fallback timeout to prevent infinite waiting
				setTimeout( () => {
					if ( ! isInitialized ) {
						const fallbackVariables =
							select( STORE_NAME )?.getVariables();
						if ( fallbackVariables ) {
							isInitialized = true;
							cleanup();
							setupDiviIntegration();
						}
					}
				}, 3000 );
			}
		} catch ( error ) {
			// Handle errors gracefully with retry limit
			if ( retryCount < maxRetries ) {
				retryCount++;
				setTimeout( checkStoreAndInitialize, 100 );
			}
		}
	};

	// Start the initialization check
	checkStoreAndInitialize();
};

waitForStoreInit();