/**
 * Customer Info Module for Cart Recovery
 *
 * Captures customer email, first name, and last name during checkout
 * and sends to REST API for abandoned cart recovery.
 *
 * @package EDD\Pro\CartRecovery
 * @since 3.6.5
 */

/**
 * Localized configuration from wp_localize_script
 *
 * @type {Object}
 */
const config = window.eddCartRecovery || {};

/**
 * State object to track customer info and prevent duplicate requests
 *
 * @type {Object}
 */
const state = {
	lastSentData: { email: '', first_name: '', last_name: '' },
	isSending: false,
	pendingCapture: false,
};

/**
 * Captures and sends customer info to the REST API
 *
 * @param {boolean} force - Force capture even if data hasn't changed (for periodic checks)
 * @return {Promise<void>}
 */
const captureCustomerInfo = async ( force = false ) => {
	// If already sending, mark that we need to capture again after this completes.
	if ( state.isSending ) {
		state.pendingCapture = true;
		return;
	}

	const form = document.getElementById( 'edd_purchase_form' );
	if ( ! form ) {
		return;
	}

	// Get field values.
	const emailField = form.querySelector( '[name="edd_email"]' );
	const firstNameField = form.querySelector( '[name="edd_first"]' );
	const lastNameField = form.querySelector( '[name="edd_last"]' );

	const data = {
		email: emailField?.value?.trim() || '',
		first_name: firstNameField?.value?.trim() || '',
		last_name: lastNameField?.value?.trim() || '',
	};

	// Require at least email to send (don't send partial name data alone).
	if ( ! data.email ) {
		return;
	}

	// Check if data has changed since last send (unless forced).
	if (
		! force &&
		data.email === state.lastSentData.email &&
		data.first_name === state.lastSentData.first_name &&
		data.last_name === state.lastSentData.last_name
	) {
		return;
	}

	state.isSending = true;

	try {
		const response = await fetch( `${ config.restEndpoint }/customer-info`, {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
				'X-EDD-Cart-Token': config.token,
				'X-EDD-Cart-Timestamp': config.timestamp,
				'X-WP-Nonce': config.nonce,
			},
			credentials: 'same-origin',
			body: JSON.stringify( data ),
		} );

		if ( response.ok ) {
			const responseData = await response.json().catch( () => ( {} ) );

			// Update token and timestamp for next request.
			if ( responseData.token ) {
				config.token = responseData.token;
			}
			if ( responseData.timestamp ) {
				config.timestamp = responseData.timestamp;
			}

			// Only update lastSentData after successful send.
			state.lastSentData = { ...data };

			// Notify other modules that customer info was captured.
			// This allows the heartbeat to start if it hasn't yet.
			document.dispatchEvent( new CustomEvent( 'edd_acr_customer_captured' ) );
		} else {
			const errorData = await response.json().catch( () => ( {} ) );
			console.debug( '[EDD ACR] Failed to capture customer info:', errorData.error );
		}
	} catch ( error ) {
		console.debug( '[EDD ACR] Error capturing customer info:', error );
	} finally {
		state.isSending = false;

		// If another capture was requested while we were sending, trigger it now.
		if ( state.pendingCapture ) {
			state.pendingCapture = false;
			// Use setTimeout to avoid recursive promise chain.
			setTimeout( () => captureCustomerInfo(), 100 );
		}
	}
};

/**
 * Handler for change events
 *
 * Fires when a field value changes AND the field loses focus.
 * No debouncing needed as change events are already "debounced" by user behavior.
 *
 * @return {void}
 */
const handleFieldChange = () => {
	const form = document.getElementById( 'edd_purchase_form' );
	if ( ! form ) {
		return;
	}

	const emailField = form.querySelector( '[name="edd_email"]' );
	const hasEmail = emailField?.value?.trim();

	// Only send if we have an email.
	if ( hasEmail ) {
		captureCustomerInfo();
	}
};

/**
 * Initializes the customer info capture system
 *
 * @return {void}
 */
export const init = () => {
	const form = document.getElementById( 'edd_purchase_form' );
	if ( ! form ) {
		return;
	}

	// Field names to monitor.
	const fieldNames = [ 'edd_email', 'edd_first', 'edd_last' ];

	fieldNames.forEach( ( fieldName ) => {
		const field = form.querySelector( `[name="${ fieldName }"]` );
		if ( field ) {
			// Use 'change' event like EDD core does for email validation.
			// This fires when the value changes AND the field loses focus.
			// Perfect for capturing complete data after user finishes.
			field.addEventListener( 'change', handleFieldChange );
		}
	} );
};

/**
 * Checks if there's unsent customer info in the form fields
 *
 * Used by heartbeat to capture data that user typed but didn't tab away from.
 *
 * @return {void}
 */
export const checkForUnsent = () => {
	const form = document.getElementById( 'edd_purchase_form' );
	if ( ! form ) {
		return;
	}

	const emailField = form.querySelector( '[name="edd_email"]' );
	const firstNameField = form.querySelector( '[name="edd_first"]' );
	const lastNameField = form.querySelector( '[name="edd_last"]' );

	const currentData = {
		email: emailField?.value?.trim() || '',
		first_name: firstNameField?.value?.trim() || '',
		last_name: lastNameField?.value?.trim() || '',
	};

	// Check if current form data differs from last sent data
	const hasUnsent = currentData.email && (
		currentData.email !== state.lastSentData.email ||
		currentData.first_name !== state.lastSentData.first_name ||
		currentData.last_name !== state.lastSentData.last_name
	);

	if ( hasUnsent ) {
		captureCustomerInfo();
	}
};

/**
 * Cleans up the customer info capture system
 *
 * Exposed for testing purposes.
 *
 * @return {void}
 */
export const cleanup = () => {
	const form = document.getElementById( 'edd_purchase_form' );
	if ( ! form ) {
		return;
	}

	const fieldNames = [ 'edd_email', 'edd_first', 'edd_last' ];
	fieldNames.forEach( ( fieldName ) => {
		const field = form.querySelector( `[name="${ fieldName }"]` );
		if ( field ) {
			field.removeEventListener( 'change', handleFieldChange );
		}
	} );
};
