/**
 * Transforms <form> POST calls content to JSON object.
 *
 * @package EaLab\WP_Deployer
 * @author Quang-Minh DANG <quang-minh@emerya.fr>
 */

/**
 * List of callbacks launched before submitting.
 *
 * @type {Function[]}
 */
const formPreSubmitCallbacks = [];

/**
 * List of callbacks launched after submitting.
 *
 * @type {Function[]}
 */
const formSubmittedCallbacks = [];

/**
 * Gets the form data as a JSON string.
 *
 * This is to be used with PostFormDataAsJsonParser.php.
 * This is useful to work around the max_input_vars limitation.
 *
 * @param {FormData} formData The form data to process.
 *
 * @returns {string}
 */
const getPostFormDataAsJson = ( formData ) => {
	const payload = {};

	for ( const [fieldName, fieldValue] of formData.entries() ) {
		if ( payload.hasOwnProperty( fieldName ) ) {
			payload[fieldName].push( fieldValue );
			continue;
		}

		payload[fieldName] = [fieldValue];
	}

	return JSON.stringify( payload );
}

/**
 * Registers a callback for when a submission is done.
 *
 * @param {Function} callback A callback function.
 */
const registerPostFormDataPreSubmitCallback = ( callback ) => {
	formPreSubmitCallbacks.push( callback );
};

/**
 * Registers a callback for when a submission is done.
 *
 * @param {Function} callback A callback function.
 */
const registerPostFormDataSubmittedCallback = ( callback ) => {
	formSubmittedCallbacks.push( callback );
};

jQuery( document ).ready( function ( $ ) {
	$( "form.submitted-as-json" ).each( function () {
		// This is an optional message that will launch the "confirm" modal on submit when set.
		const maybeConfirmMessage = $( this ).data( "confirmMessage" );

		$( this ).on( "submit", ( event ) => {
			event.preventDefault();

			if ( maybeConfirmMessage && ! confirm( maybeConfirmMessage ) ) {
				// Abort the submission.
				return;
			}

			const formElement = event.currentTarget;
			const formData = new FormData( formElement );
			const action = formElement.getAttribute( 'action' );
			const method = formElement.getAttribute( 'method' );

			const headers = new Headers();
			headers.append( 'Content-Type', 'text/plain' );

			// Convert the FormData to a format not limited by max_input_vars.
			const formDataAsJson = getPostFormDataAsJson( formData );

			const fetchInit = {
				body: formDataAsJson, method: method, headers: headers,
			};

			for ( const callback of formPreSubmitCallbacks ) {
				const stop = callback( formElement, action, fetchInit );

				if ( stop ) {
					break;
				}
			}

			fetch( action, fetchInit )
				.then( ( response ) => {
					for ( const callback of formSubmittedCallbacks ) {
						const stop = callback( formElement, action, fetchInit, response );

						if ( stop ) {
							break;
						}
					}
				} );
		} )
	} );
} );
