/* global wpforms_admin, wpforms_settings, wpforms_admin_edit_entry, wpf, wpforms, tinyMCE */

/**
 * @param wpforms_admin_edit_entry.strings.continue_editing
 * @param wpforms_admin_edit_entry.strings.entry_delete_file
 * @param wpforms_admin_edit_entry.strings.entry_empty_file
 * @param wpforms_admin_edit_entry.strings.msg_saved
 * @param wpforms_admin_edit_entry.strings.view_entry
 * @param wpforms_admin_edit_entry.strings.view_entry_url
 * @param wpforms_settings.val_number
 * @param wpforms_settings.val_phone
 */

// noinspection ES6ConvertVarToLetConst
/**
 * WPForms Edit Entry function.
 *
 * @since 1.6.0
 */
var WPFormsEditEntry = window.WPFormsEditEntry || ( function( document, window, $ ) { // eslint-disable-line
	/**
	 * Elements reference.
	 *
	 * @since 1.6.0
	 *
	 * @type {Object}
	 */
	const el = {
		$editForm:     $( '#wpforms-edit-entry-form' ),
		$submitButton: $( '#wpforms-edit-entry-update' ),
	};

	/**
	 * Runtime vars.
	 *
	 * @since 1.6.0
	 *
	 * @type {Object}
	 */
	const vars = {};

	/**
	 * Public functions and properties.
	 *
	 * @since 1.6.0
	 *
	 * @type {Object}
	 */
	const app = {

		/**
		 * Start the engine.
		 *
		 * @since 1.6.0
		 */
		init() {
			$( app.ready );
		},

		/**
		 * Document ready.
		 *
		 * @since 1.6.0
		 */
		ready() {
			vars.nonce = el.$editForm.find( 'input[name="nonce"]' ).val();
			vars.entryId = el.$editForm.find( 'input[name="wpforms[entry_id]"]' ).val();

			app.initSavedFormData();
			app.events();

			wpf.initTooltips();
		},

		/**
		 * Register JS events.
		 *
		 * @since 1.6.0
		 */
		events() {
			// Submit the form.
			el.$submitButton.on( 'click', app.clickUpdateButton );

			// Submit result.
			el.$editForm
				.on( 'wpformsAjaxBeforeSubmit', app.validateFields ) // Validate fields before submitting.
				.on( 'wpformsAjaxSubmitFailed', app.submitFailed ) // Submit Failed, display the errors.
				.on( 'wpformsAjaxSubmitSuccess', app.submitSuccess ); // Submit Success.

			// Prevent lost not saved changes.
			$( window ).on( 'beforeunload', app.beforeUnload );

			// Confirm file deletion.
			$( document ).on( 'click', '.wpforms-edit-entry-field-file-upload .delete', app.fileDelete );
			$( document ).on( 'click', '.wpforms-edit-entry-field-camera .delete', app.fileDelete );
		},

		/**
		 * Store form data for further comparison.
		 *
		 * @since 1.6.0
		 */
		initSavedFormData() {
			vars.savedFormData = el.$editForm.serialize();
		},

		/**
		 * Prevent lost not saved changes.
		 *
		 * @since 1.6.0
		 *
		 * @param {Object} event Event object.
		 *
		 * @return {string|void} Not empty string if needed to display standard alert.
		 */
		beforeUnload( event ) {
			if ( el.$editForm.serialize() === vars.savedFormData ) {
				return;
			}

			event.returnValue = 'Leave site?';

			return event.returnValue;
		},

		/**
		 * Click the Update button event handler.
		 *
		 * @since 1.6.0
		 *
		 * @param {Object} event Event object.
		 */
		clickUpdateButton( event ) {
			event.preventDefault();

			el.$submitButton.prop( 'disabled', true );

			app.preSubmitActions();

			// Hide all errors.
			app.hideErrors();

			// Add a referer hidden field to cover a case when the browser referer is stripped out by the server.
			el.$editForm.append( $( '<input>', { type: 'hidden', name: '_wp_http_referer', value: wpf.updateQueryString( '_wp_http_referer', null ) } ) );

			wpforms.formSubmitAjax( el.$editForm );
		},

		/**
		 * Some fields requires special pre-submit actions.
		 *
		 * @since 1.6.0
		 */
		preSubmitActions() {
			const formID = el.$editForm.data( 'formid' );

			// Fix for Smartphone fields.
			$( '.wpforms-smart-phone-field' ).trigger( 'input' );

			// Delete files from the list.
			$( '.wpforms-edit-entry-field-file-upload a.disabled,.wpforms-edit-entry-field-camera a.disabled' ).each( function() {
				$( this ).parent().remove();
			} );

			$( '.wpforms-field-file-upload,.wpforms-field-camera' ).each( function() {
				const $this = $( this );

				if ( $this.is( ':empty' ) ) {
					$this.closest( '.wpforms-edit-entry-field-file-upload, .wpforms-edit-entry-field-camera' ).addClass( 'empty' );
					$this.html( $( '<span>', {
						class: 'wpforms-entry-field-value',
						text: wpforms_admin_edit_entry.strings.entry_empty_file,
					} ) );
				}
			} );

			// Update Rich Text fields content.
			$( '.wpforms-field-richtext' ).each( function() {
				const fieldID = $( this ).data( 'field-id' ),
					editor = tinyMCE.get( 'wpforms-' + formID + '-field_' + fieldID );

				if ( editor ) {
					editor.save();
				}
			} );
		},

		/**
		 * Submit Failed, display the errors.
		 *
		 * @since 1.6.0
		 *
		 * @param {Object} event    Event object.
		 * @param {Object} response Response data.
		 */
		submitFailed( event, response ) {
			app.displayErrors( response );

			$.alert( {
				title: wpforms_admin.heads_up,
				content: response.data.errors.general,
				icon: 'fa fa-info-circle',
				type: 'orange',
				buttons: {
					confirm: {
						text: wpforms_admin_edit_entry.strings.continue_editing,
						btnClass: 'btn-confirm',
						keys: [ 'enter' ],
					},
					cancel: {
						text    : wpforms_admin_edit_entry.strings.view_entry,
						action() {
							window.location.href = wpforms_admin_edit_entry.strings.view_entry_url;
						},
					},
				},
			} );
		},

		/**
		 * Submit Success.
		 *
		 * @since 1.6.0
		 *
		 * @param {Object} event    Event object.
		 * @param {Object} response Response data.
		 */
		submitSuccess( event, response ) {
			app.initSavedFormData();

			// Display alert only if some changes were made.
			if ( typeof response.data === 'undefined' ) {
				return;
			}

			// Update modified value.
			$( '#wpforms-entry-details .wpforms-entry-modified .date-time' ).text( response.data.modified );

			// Alert message.
			$.alert( {
				title: wpforms_admin_edit_entry.strings.success,
				content: wpforms_admin_edit_entry.strings.msg_saved,
				icon: 'fa fa-info-circle',
				type: 'green',
				buttons: {
					confirm: {
						text: wpforms_admin_edit_entry.strings.continue_editing,
						btnClass: 'btn-confirm',
						keys: [ 'enter' ],
					},
					cancel: {
						text    : wpforms_admin_edit_entry.strings.view_entry,
						action() {
							window.location.href = wpforms_admin_edit_entry.strings.view_entry_url;
						},
					},
				},
			} );
		},

		/**
		 * Hide all errors.
		 *
		 * @since 1.6.0
		 */
		hideErrors() {
			el.$editForm.find( '.wpforms-field.wpforms-has-error' ).removeClass( 'wpforms-has-error' );
			el.$editForm.find( '.wpforms-error:not(label)' ).removeClass( 'wpforms-error' );
			el.$editForm.find( 'label.wpforms-error, em.wpforms-error' ).addClass( 'wpforms-hidden' );
		},

		/**
		 * Display validation errors arrived from the server.
		 *
		 * @since 1.6.0
		 *
		 * @param {Object} response Response data.
		 */
		displayErrors( response ) {
			let errors = response.data && ( 'errors' in response.data ) ? response.data.errors : null;

			if ( wpf.empty( errors ) || wpf.empty( errors.field ) ) {
				return;
			}

			errors = errors.field;

			Object.keys( errors ).forEach( function( fieldID ) {
				// Display field error.
				app.displayFieldError( fieldID, errors[ fieldID ] );

				// Display complex field errors.
				app.displaySubfieldsErrors( fieldID, errors[ fieldID ] );
			} );
		},

		/**
		 * Display field validation error.
		 *
		 * @since 1.6.0
		 *
		 * @param {string} fieldID    Field ID.
		 * @param {string} fieldError Field error.
		 */
		displayFieldError( fieldID, fieldError ) {
			if (
				typeof fieldError !== 'string' ||
				( wpf.empty( fieldID ) && fieldID !== '0' ) ||
				wpf.empty( fieldError )
			) {
				return;
			}

			const formID = el.$editForm.data( 'formid' ),
				fieldInputID = 'wpforms-' + formID + '-field_' + fieldID,
				errorLabelID = fieldInputID + '-error',
				$fieldContainer = el.$editForm.find( '#' + fieldInputID + '-container' ),
				$errLabel = el.$editForm.find( '#' + errorLabelID );

			$fieldContainer.addClass( 'wpforms-has-error' );
			$( '#' + fieldInputID ).addClass( 'wpforms-error' );

			if ( $errLabel.length > 0 ) {
				$errLabel.html( fieldError ).removeClass( 'wpforms-hidden' );
				return;
			}

			$fieldContainer.append( '<label id="' + errorLabelID + '" class="wpforms-error">' + fieldError + '</label>' );
		},

		/**
		 * Display validation errors for subfields.
		 *
		 * @since 1.6.0
		 *
		 * @param {string} fieldID     Field ID.
		 * @param {Object} fieldErrors Field errors.
		 */
		displaySubfieldsErrors( fieldID, fieldErrors ) {
			if ( typeof fieldErrors !== 'object' || wpf.empty( fieldErrors ) || wpf.empty( fieldID ) ) {
				return;
			}

			const formID = el.$editForm.data( 'formid' ),
				fieldInputID = 'wpforms-' + formID + '-field_' + fieldID,
				$fieldContainer = el.$editForm.find( '#' + fieldInputID + '-container' );

			Object.keys( fieldErrors ).forEach( function( key ) {
				const error = fieldErrors[ key ];

				if ( typeof error !== 'string' || error === '' ) {
					return;
				}

				const fieldInputName = 'wpforms[fields][' + fieldID + '][' + key + ']',
					errorLabelID = 'wpforms-' + formID + '-field_' + fieldID + '-' + key + '-error',
					$errLabel = el.$editForm.find( '#' + errorLabelID );

				if ( ! $fieldContainer.hasClass( 'wpforms-has-error' ) ) {
					$fieldContainer.addClass( 'wpforms-has-error' );
				}

				if ( $errLabel.length > 0 ) {
					$fieldContainer.find( '[name="' + fieldInputName + '"]' ).addClass( 'wpforms-error' );
					$errLabel.html( error ).removeClass( 'wpforms-hidden' );
					return;
				}

				const errorLabel = '<label id="' + errorLabelID + '" class="wpforms-error">' + error + '</label>';

				if ( $fieldContainer.hasClass( 'wpforms-field-likert_scale' ) ) {
					$fieldContainer.find( 'tr' ).eq( key.replace( /r/, '' ) ).after( errorLabel );
					return;
				}

				$fieldContainer.find( '[name="' + fieldInputName + '"]' ).addClass( 'wpforms-error' ).after( errorLabel );
			} );
		},

		/**
		 * Confirm file deletion.
		 *
		 * @since 1.6.6
		 *
		 * @param {Object} event Event object.
		 */
		fileDelete( event ) {
			event.preventDefault();

			const $element = $( this ),
				$fileInput = $element.parent().find( 'a' ).first();

			// Trigger alert modal to confirm.
			$.confirm( {
				title: false,
				content:  wpforms_admin_edit_entry.strings.entry_delete_file.replace( '{file_name}', $fileInput.html() ),
				icon: 'fa fa-exclamation-circle',
				type: 'orange',
				buttons: {
					confirm: {
						text: wpforms_admin.ok,
						btnClass: 'btn-confirm',
						keys: [ 'enter' ],
						action() {
							$fileInput.html( $fileInput.text().strike() );
							$fileInput.addClass( 'disabled' );
							$element.parent().find( 'input[type="hidden"]' ).remove();
							$element.remove();
						},
					},
					cancel: {
						text: wpforms_admin.cancel,
						keys: [ 'esc' ],
					},
				},
			} );
		},

		/**
		 * Validate fields before submitting.
		 * Use event.preventDefault() to prevent form submission.
		 *
		 * @since 1.8.8
		 *
		 * @param {Object} event Event object.
		 */
		validateFields( event ) {
			app.validateSmartPhoneFields( event );
			app.validateNumbersFields( event );
		},

		/**
		 * Validate "Smart" phone fields before submitting.
		 *
		 * @since 1.8.8
		 *
		 * @param {Object} event Event object.
		 */
		validateSmartPhoneFields( event ) {
			// Loop through each "Smart" phone field.
			$( '.wpforms-smart-phone-field' ).each( function() {
				// Allow empty fields.
				if ( ! $( this ).val() ) {
					return;
				}

				const fieldID = $( this ).closest( '.wpforms-field' ).data( 'field-id' );
				const iti = window.intlTelInput?.getInstance( this );
				const result = $( this ).triggerHandler( 'validate' ) || iti?.isValidNumberPrecise();

				// If the phone number is not valid, prevent form submission and display an error.
				if ( ! result ) {
					event.preventDefault();
					app.displayFieldError( fieldID, wpforms_settings.val_phone );
				}
			} );
		},

		/**
		 * Validate Numbers fields before submitting.
		 *
		 * @since 1.9.4
		 *
		 * @param {Object} event Event object.
		 */
		validateNumbersFields( event ) {
			$( '.wpforms-field-number' ).each( function() {
				const $field = $( this ),
					fieldInput = $field.find( 'input[type="number"]' )[ 0 ];

				// We validate required fields on the backend to ensure CL doesn't hide the field.
				fieldInput.required = false;

				if ( fieldInput.checkValidity() ) {
					return;
				}

				const fieldID = $field.data( 'field-id' ),
					errorMessage = fieldInput.validity.badInput ? wpforms_settings.val_number : fieldInput.validationMessage;

				app.displayFieldError( fieldID, errorMessage );
				event.preventDefault();
			} );
		} };

	// Provide access to public functions/properties.
	return app;
}( document, window, jQuery ) );

// Initialize.
WPFormsEditEntry.init();
