<?php
/**
 * Main class to load the entries management related functionalities.
 *
 * @since 1.3.0
 * @package sureforms-pro
 */

namespace SRFM_Pro\Inc\Extensions;

use SRFM\Inc\Database\Tables\Entries;
use SRFM\Inc\Form_Submit;
use SRFM\Inc\Helper;
use SRFM_Pro\Inc\Databases\Entries_Pro;
use SRFM_Pro\Inc\Helper as Pro_Helper;
use SRFM_Pro\Inc\Traits\Get_Instance;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * Entries Management Class.
 *
 * @since 1.3.0
 */
class Entries_Management {
	use Get_Instance;

	/**
	 * Entries Management constructor.
	 *
	 * @since 1.3.0
	 */
	public function __construct() {
		// Filter hooks.
		add_filter( 'srfm_entry_logs_markup', [ $this, 'render_entry_logs' ] );

		// Action hooks.
		add_action( 'admin_init', [ $this, 'save_edit_entry_data' ] );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
		add_action( 'srfm_after_entry_postbox_title', [ $this, 'display_bulk_resend_notification_button' ] );
		add_action( 'srfm_after_entry_submission_info', [ $this, 'edit_entry_resend_notification_button' ] );
		add_action( 'srfm_before_entry_submission_info', [ $this, 'edit_entry_notes_markup' ] );
		add_action( 'srfm_after_entry_postbox_title', [ $this, 'edit_entry_button_markup' ] );
		add_action( 'srfm_before_entry_form_closing_tag', [ $this, 'edit_entry_dialog_markup' ] );

		// AJAX hooks.
		add_action( 'wp_ajax_sureforms_pro_navigate_entry_notes', [ $this, 'navigate_entry_notes' ] );
		add_action( 'wp_ajax_sureforms_pro_navigate_entry_logs', [ $this, 'navigate_entry_logs' ] );
		add_action( 'wp_ajax_sureforms_pro_resend_email_notifications', [ $this, 'resend_email_notifications' ] );
		add_action( 'wp_ajax_sureforms_pro_save_entry_notes', [ $this, 'save_entry_notes' ] );
		add_action( 'wp_ajax_sureforms_pro_entry_delete_file', [ $this, 'entry_delete_file' ] );

		add_action( 'srfm_before_delete_entry', [ $this, 'before_delete_entry' ] );

		// Initialize the class for the edit entry fields markup.
		Edit_Entry_Fields_Markup::init();
	}

	/**
	 * Enqueue entries management assets.
	 *
	 * @param string $hook_prefix The hook prefix.
	 * @since 1.3.0
	 * @return void
	 */
	public function enqueue_assets( $hook_prefix ) {
		if ( 'sureforms_page_sureforms_entries' !== $hook_prefix ) {
			return;
		}

		$file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
		$dir_name    = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
		$css_uri     = SRFM_PRO_URL . 'assets/css/' . $dir_name . '/';
		$js_uri      = SRFM_PRO_URL . 'assets/js/' . $dir_name . '/';

		wp_enqueue_style( SRFM_PRO_SLUG . '-entries', $css_uri . 'entries' . $file_prefix . '.css', [], SRFM_PRO_VER );
		wp_enqueue_style( SRFM_PRO_SLUG . '-entry-fields', $css_uri . 'entry-fields' . $file_prefix . '.css', [], SRFM_PRO_VER );
		wp_enqueue_script( SRFM_PRO_SLUG . '-entries', $js_uri . 'entries' . $file_prefix . '.js', [], SRFM_PRO_VER, true );

		wp_localize_script(
			SRFM_PRO_SLUG . '-entries',
			'srfm_pro_entries',
			[
				'entryID'  => isset( $_GET['entry_id'] ) ? absint( wp_unslash( $_GET['entry_id'] ) ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is skipped here as we don't get nonce in the URL here and we are not doing database query.
				'ajaxURLs' => [
					'saveNotes'          => add_query_arg(
						[
							'action'   => 'sureforms_pro_save_entry_notes',
							'security' => wp_create_nonce( '_srfm_entry_notes_nonce' ),
						],
						admin_url( 'admin-ajax.php' )
					),
					'navigateNotes'      => add_query_arg(
						[
							'action'   => 'sureforms_pro_navigate_entry_notes',
							'security' => wp_create_nonce( '_srfm_navigate_entry_notes_nonce' ),
						],
						admin_url( 'admin-ajax.php' )
					),
					'navigateLogs'       => add_query_arg(
						[
							'action'   => 'sureforms_pro_navigate_entry_logs',
							'security' => wp_create_nonce( '_srfm_navigate_entry_logs_nonce' ),
						],
						admin_url( 'admin-ajax.php' )
					),
					'resendNotification' => add_query_arg(
						[
							'action'   => 'sureforms_pro_resend_email_notifications',
							'security' => wp_create_nonce( '_srfm_resend_email_notifications_nonce' ),
						],
						admin_url( 'admin-ajax.php' )
					),
					'deleteFile'         => add_query_arg(
						[
							'action'   => 'sureforms_pro_entry_delete_file',
							'security' => wp_create_nonce( '_srfm_entry_delete_file' ),
						],
						admin_url( 'admin-ajax.php' )
					),
				],
			]
		);
	}

	/**
	 * Save edited entry data and update the corresponding logs.
	 *
	 * This method processes the incoming POST request to edit an entry, verifies the nonce,
	 * sanitizes the data, and logs any changes made to the entry. If no changes are detected,
	 * it resets the logs.
	 *
	 * @since 1.3.0
	 * @return void
	 */
	public function save_edit_entry_data() {
		if ( empty( $_POST['srfm-edit-entry-nonce'] ) || empty( $_POST['entry_id'] ) ) {
			// Bail early if we don't have nonce key or entry id key.
			return;
		}

		$entry_id = absint( wp_unslash( $_POST['entry_id'] ) );

		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['srfm-edit-entry-nonce'] ) ), 'srfm-edit-entry-' . $entry_id ) ) {
			return;
		}

		$data = Helper::sanitize_by_field_type( wp_unslash( $_POST ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We are sanitizing using our custom function.

		$instance = Entries::get_instance();

		/* translators: Here %s means the users display name. */
		$instance->add_log( sprintf( __( 'Entry edited by %s', 'sureforms-pro' ), wp_get_current_user()->display_name ) ); // Init log.

		$changed = 0;
		$edited  = [];
		if ( ! empty( $data ) && is_array( $data ) ) {

			$form_data = Helper::get_array_value( $instance::get( $entry_id )['form_data'] );

			// Get the form data and merge it with the submitted data.
			$_data = array_merge( $form_data, $data );

			foreach ( $_data as $field_name => $v ) {
				if ( ! array_key_exists( $field_name, $form_data ) && ( false === strpos( $field_name, '-lbl-' ) ) ) {
					continue;
				}

				/**
				 * Action fired just before updating individual entry field data.
				 *
				 * This action hook allows developers to perform custom operations before a form field
				 * value is updated in the entry logs. Common use cases include:
				 * - Updating entry logs with field-specific change tracking
				 * - Processing complex field types like repeaters or file uploads
				 * - Adding custom validation or data transformation
				 * - Integrating with external systems
				 *
				 * @param array $args {
				 *     Arguments passed to the action hook.
				 *     @type string     $field_name      The name/key of the field being updated
				 *     @type mixed      $field_value     The new value being saved for this field
				 *     @type array      $saved_form_data The existing form data before update
				 *     @type array      $current_data    The complete new form data being saved
				 *     @type object     $entry_instance  Instance of the Entries class
				 *     @type int        $changed         Reference to counter tracking number of changes
				 * }
				 * @since 1.11.0
				 */
				do_action(
					'srfm_pro_before_update_entry_data',
					[
						'field_name'      => $field_name,
						'field_value'     => $v,
						'saved_form_data' => $form_data,
						'current_data'    => $_data,
						'entry_instance'  => $instance,
						'changed'         => &$changed,
					]
				);

				// If the field is an array, encode the values. This is to add support for multi-upload field.
				if ( is_array( $v ) ) {
					if ( false !== strpos( $field_name, 'srfm-upload' ) ) {
						$edited[ $field_name ] = array_map(
							static function ( $val ) {
								return rawurlencode( esc_url_raw( $val ) );
							},
							$v
						);
						// Skip the rest of the loop if we are handling uploads field.
						continue;
					}

					if ( false !== strpos( $field_name, 'srfm-repeater' ) ) {
						// If the field is a repeater field, then we need to process the repeater field.
						$edited[ $field_name ] = $v;
						continue;
					}

					// If the field is a repeater field, then we need to process the repeater field.

					// Compare submitted array and previously saved array.
					// Retrieve the previously saved value for the field from the database.
					$previous_saved_value = Helper::get_string_value( $form_data[ $field_name ] );

					// Determine the separator used in the saved value for backward compatibility.
					// If the string contains " | ", split it using " | "; otherwise, split it using ",".
					$prev_value = strpos( $previous_saved_value, '|' ) !== false
						? explode( ' | ', $previous_saved_value )
						: explode( ',', $previous_saved_value );

					$current_value = $v;

					// Sort both arrays to compare them.
					sort( $prev_value );
					sort( $current_value );

					// Convert both arrays to string to compare them.
					$prev_value    = implode( ' | ', $prev_value );
					$current_value = implode( ' | ', $current_value );

					if ( md5( $current_value ) === md5( $prev_value ) ) {
						// If both arrays are same then skip the rest of the loop.
						$edited[ $field_name ] = $prev_value;
						continue;
					}
					$edited[ $field_name ] = implode( ' | ', $v );

				} else {
					$edited[ $field_name ] = htmlspecialchars( $v );
				}

				if ( false !== strpos( $field_name, 'srfm-checkbox' ) && empty( $v ) && ! isset( $form_data[ $field_name ] ) ) {
					unset( $edited[ $field_name ] );
					continue;
				}

				$log = is_array( $v ) ? implode( ' | ', $v ) : $v;

				if ( ! isset( $form_data[ $field_name ] ) ) {
					// &#8594; is html entity for arrow -> sign.
					$instance->update_log( $instance->get_last_log_key(), null, [ '<strong>' . Helper::get_field_label_from_key( $field_name ) . ': </strong> "" &#8594; ' . $log ] );
					$changed++;
					continue;
				}

				if ( $form_data[ $field_name ] === $edited[ $field_name ] ) {
					continue;
				}

				$form_data_log = Helper::get_string_value( $form_data[ $field_name ] );

				// &#8594; is html entity for arrow -> sign. Use HTML template instead of inline HTML string.
				ob_start(); ?>
				<strong><?php echo esc_html( Helper::get_field_label_from_key( $field_name ) . ': ' ); ?></strong> <del><?php echo esc_html( $form_data_log ); ?></del> &#8594; <?php echo esc_html( $log ); ?>
				<?php
				$srfm_formatted_log = ob_get_clean();
				$srfm_formatted_log = is_string( $srfm_formatted_log ) ? $srfm_formatted_log : '';
				$instance->update_log( $instance->get_last_log_key(), null, [ $srfm_formatted_log ] );
				$changed++;
			}
		}

		if ( ! $changed ) {
			// Reset logs to zero if no valid changes are made.
			$instance->reset_logs();
		}

		$instance::update(
			$entry_id,
			[
				'form_data' => $edited,
				'logs'      => $instance->get_logs(),
			]
		);

		wp_safe_redirect( remove_query_arg( 'edit' ) );
		exit;
	}

	/**
	 * Ajax callback to provide entry logs navigation response.
	 *
	 * @since 1.3.0
	 * @return void
	 */
	public function navigate_entry_logs() {
		/**
		 * Nonce verification.
		 * Need to add this code separately to suppress nonce verification phpcs error below.
		 */
		if ( ! check_ajax_referer( '_srfm_navigate_entry_logs_nonce', 'security' ) ) {
			wp_send_json_error( [ 'message' => $this->get_error_msg( 'nonce' ) ] );
		}

		$entry_id = $this->validate_entry_request();
		$entry    = Entries::get( $entry_id );
		$logs     = ! empty( $entry['logs'] ) ? Helper::get_array_value( $entry['logs'] ) : [];

		$type       = ! empty( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : 'next';
		$delete_log = isset( $_POST['deleteLog'] ) ? absint( wp_unslash( $_POST['deleteLog'] ) ) : false; // Log key-ID to delete.

		if ( 'next' === $type ) {
			$current_page = isset( $_POST['nextPage'] ) ? absint( wp_unslash( $_POST['nextPage'] ) ) : 1;
		} else {
			$current_page = isset( $_POST['prevPage'] ) ? absint( wp_unslash( $_POST['prevPage'] ) ) : 1;
		}

		if ( false !== $delete_log && isset( $logs[ $delete_log ] ) ) {
			unset( $logs[ $delete_log ] );
			$logs = array_values( $logs );

			Entries::get_instance()->use_update(
				[ 'logs' => $logs ],
				[ 'ID' => absint( $entry_id ) ]
			);

			--$current_page;
		}

		$paginate_logs = self::paginate_array( $logs, $current_page );

		/**
		 * Get the items for the current page.
		 *
		 * @var array<array<mixed>> $items
		 */
		$items = $paginate_logs['items'];

		ob_start();
		$this->entry_logs_table_markup( $items );
		$markup = ob_get_clean();

		wp_send_json_success(
			[
				'markup'      => $markup,
				'totalPages'  => $paginate_logs['total_pages'],
				'currentPage' => $paginate_logs['current_page'],
				'nextPage'    => $paginate_logs['next_page'],
				'prevPage'    => $paginate_logs['prev_page'],
			]
		);
	}

	/**
	 * Ajax callback to provide entry notes navigation response.
	 *
	 * @since 1.3.0
	 * @return void
	 */
	public function navigate_entry_notes() {
		/**
		 * Nonce verification.
		 * Need to add this code separately to suppress nonce verification phpcs error below.
		 */
		if ( ! check_ajax_referer( '_srfm_navigate_entry_notes_nonce', 'security' ) ) {
			wp_send_json_error( [ 'message' => $this->get_error_msg( 'nonce' ) ] );
		}

		$entry_id    = $this->validate_entry_request();
		$entry       = Entries::get( $entry_id );
		$type        = ! empty( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : 'next';
		$delete_note = isset( $_POST['deleteNote'] ) ? absint( wp_unslash( $_POST['deleteNote'] ) ) : false; // Note key-ID to delete.

		if ( 'next' === $type ) {
			$current_page = isset( $_POST['nextPage'] ) ? absint( wp_unslash( $_POST['nextPage'] ) ) : 1;
		} else {
			$current_page = isset( $_POST['prevPage'] ) ? absint( wp_unslash( $_POST['prevPage'] ) ) : 1;
		}

		$notes = ! empty( $entry['notes'] ) ? Helper::get_array_value( $entry['notes'] ) : [];

		if ( false !== $delete_note ) {
			// Extract the 'timestamp' column and search for the desired value.
			$note_key = array_search( $delete_note, array_column( $notes, 'timestamp' ), true );

			if ( isset( $notes[ $note_key ] ) ) {
				unset( $notes[ $note_key ] );
				$notes = array_values( $notes );

				Entries_Pro::get_instance()->use_update(
					[ 'notes' => $notes ],
					[ 'ID' => absint( $entry_id ) ]
				);
			}

			--$current_page;
		}

		$paginate_notes = self::paginate_array( $notes, $current_page, 2 );

		// Get the items for the current page.
		$entry_notes = $paginate_notes['items'];

		ob_start();
		if ( ! empty( $entry_notes ) && is_array( $entry_notes ) ) {
			foreach ( $entry_notes as $entry_note ) {
				$this->entry_note_item_markup( $entry_note );
			}
		}
		$markup = ob_get_clean();

		wp_send_json_success(
			[
				'markup'      => $markup,
				'totalPages'  => $paginate_notes['total_pages'],
				'currentPage' => $paginate_notes['current_page'],
				'nextPage'    => $paginate_notes['next_page'],
				'prevPage'    => $paginate_notes['prev_page'],
			]
		);
	}

	/**
	 * Resend email notifications for specified entry IDs and log the results.
	 *
	 * This method checks user permissions, validates input, verifies a nonce, and processes the
	 * resending of email notifications for specified entries. It logs successes and failures for each
	 * notification sent, returning a summary of the results.
	 *
	 * @since 1.3.0
	 * @return void
	 */
	public function resend_email_notifications() {
		if ( ! Helper::current_user_can() ) {
			wp_send_json_error( $this->resend_email_notifications_alert( $this->get_error_msg( 'permission' ), false ) );
		}

		if ( empty( $_POST['entry_ids'] ) && empty( $_POST['form_id'] ) && empty( $_POST['email_notification'] ) ) {
			wp_send_json_error( $this->resend_email_notifications_alert( $this->get_error_msg( 'invalid' ), false ) );
		}

		/**
		 * Nonce verification.
		 */
		if ( ! check_ajax_referer( '_srfm_resend_email_notifications_nonce', 'security' ) ) {
			wp_send_json_error( $this->resend_email_notifications_alert( $this->get_error_msg( 'nonce' ), false ) );
		}

		$entry_ids = sanitize_text_field( wp_unslash( $_POST['entry_ids'] ) );
		$entry_ids = array_map( 'absint', explode( ',', $entry_ids ) );

		if ( empty( $entry_ids ) ) {
			wp_send_json_error( $this->resend_email_notifications_alert( __( 'Entry IDs cannot be empty.', 'sureforms-pro' ), false ) );
		}

		$recipient = '';
		$send_to   = ! empty( $_POST['send_to'] ) ? sanitize_text_field( wp_unslash( $_POST['send_to'] ) ) : 'default';

		if ( 'other' === $send_to ) {
			$recipient = ! empty( $_POST['recipient'] ) ? sanitize_email( wp_unslash( $_POST['recipient'] ) ) : '';

			if ( ! is_email( $recipient ) ) {
				// Bail if not a valid email address.
				wp_send_json_error( $this->resend_email_notifications_alert( __( 'You must provide a valid email for the recipient.', 'sureforms-pro' ), false ) );
			}
		}

		$form_id               = absint( wp_unslash( $_POST['form_id'] ) );
		$email_notification_id = absint( wp_unslash( $_POST['email_notification'] ) );

		$email_notification = Helper::get_array_value( get_post_meta( $form_id, '_srfm_email_notification', true ) );

		$display_name = wp_get_current_user()->display_name;

		if ( ! empty( $email_notification ) && is_array( $email_notification ) ) {
			foreach ( $email_notification as $notification ) {
				if ( absint( $notification['id'] ) !== $email_notification_id ) {
					continue;
				}

				if ( true !== $notification['status'] ) {
					// It means email notification is toggled off and we can ignore and move to next step.
					continue;
				}

				foreach ( $entry_ids as $entry_id ) {
					// We don't want the same instance here, instead we need to init new object for each entry id here.
					$entries_db = new Entries();

					/* translators: Here %1$s is email notification label and %2$s is the user display name. */
					$log_key   = $entries_db->add_log( sprintf( __( 'Resend email notification "%1$s" initiated by %2$s', 'sureforms-pro' ), esc_html( $notification['name'] ), esc_html( $display_name ) ) );
					$form_data = Helper::get_array_value( $entries_db::get( $entry_id )['form_data'] );
					$parsed    = Form_Submit::parse_email_notification_template( $form_data, $notification );

					// If user has provided recipient then reroute email to user provided recipient.
					$email_to = $recipient ? $recipient : $parsed['to'];
					$sent     = wp_mail( $email_to, $parsed['subject'], $parsed['message'], $parsed['headers'] );

					/* translators: Here, %s is email address. */
					$log_message = $sent ? sprintf( __( 'Email notification recipient: %s', 'sureforms-pro' ), esc_html( $email_to ) ) : sprintf( __( 'Failed sending email notification to %s', 'sureforms-pro' ), esc_html( $email_to ) );

					if ( is_int( $log_key ) ) {
						$entries_db->update_log( $log_key, null, [ $log_message ] );
					}

					$entries_db::update(
						$entry_id,
						[
							'logs' => $entries_db->get_logs(),
						]
					);
				}
			}
		}

		wp_send_json_success( $this->resend_email_notifications_alert( __( 'Email notification passed to the sending server.', 'sureforms-pro' ) ) );
	}

	/**
	 * Save notes for a specified entry and return the updated notes.
	 *
	 * This method checks user permissions, validates input, verifies a nonce,
	 * and saves the provided note for the specified entry. It then retrieves
	 * the updated list of notes and sends it back in the response.
	 *
	 * @since 1.3.0
	 * @return void
	 */
	public function save_entry_notes() {
		$response_data = [ 'message' => $this->get_error_msg( 'permission' ) ];

		if ( ! Helper::current_user_can() ) {
			wp_send_json_error( $response_data );
		}

		if ( empty( $_POST['note'] ) && empty( $_POST['entryID'] ) ) {
			$response_data = [ 'message' => $this->get_error_msg( 'invalid' ) ];
			wp_send_json_error( $response_data );
		}

		/**
		 * Nonce verification.
		 */
		if ( ! check_ajax_referer( '_srfm_entry_notes_nonce', 'security' ) ) {
			$response_data = [ 'message' => $this->get_error_msg( 'nonce' ) ];
			wp_send_json_error( $response_data );
		}

		$entry_id = absint( wp_unslash( $_POST['entryID'] ) );

		Entries_Pro::add_note( $entry_id, sanitize_textarea_field( wp_unslash( $_POST['note'] ) ) );

		ob_start();
		$notes = Entries::get( $entry_id )['notes'];
		if ( ! empty( $notes ) && is_array( $notes ) ) {
			foreach ( $notes as $note ) {
				$this->entry_note_item_markup( $note );
			}
		}
		$data = ob_get_clean();

		wp_send_json_success( $data );
	}

	/**
	 * Deletes a file based on the provided file URL via an AJAX request.
	 *
	 * This method handles the deletion of a file by verifying the AJAX nonce,
	 * checking if the file URL is provided, converting the file URL to a file path,
	 * and then attempting to delete the file from the server.
	 *
	 * @since 1.3.0
	 * @return void
	 */
	public function entry_delete_file() {
		if ( ! check_ajax_referer( '_srfm_entry_delete_file', 'security' ) ) {
			wp_send_json_error( [ 'message' => $this->get_error_msg( 'nonce' ) ] );
		}

		if ( empty( $_POST['file'] ) ) {
			wp_send_json_error( [ 'message' => $this->get_error_msg( 'invalid' ) ] );
		}

		$entry_id  = $this->validate_entry_request();
		$file_path = Helper::convert_fileurl_to_filepath( urldecode( esc_url_raw( wp_unslash( $_POST['file'] ) ) ) );

		if ( ! file_exists( $file_path ) ) {
			wp_send_json_error( [ 'message' => esc_html__( 'File not found.', 'sureforms-pro' ) ] );
		}

		$remove_file = Pro_Helper::delete_upload_file_from_subdir( $file_path, 'sureforms/' );

		if ( ! $remove_file ) {
			wp_send_json_error( [ 'message' => esc_html__( 'Failed to delete file.', 'sureforms-pro' ) ] );
		}

		$instance = Entries::get_instance();
		/* translators: %1$s is the file basename and %2$s is the user display name. */
		$instance->add_log( sprintf( esc_html__( 'File "%1$s" deleted by %2$s', 'sureforms-pro' ), esc_html( basename( $file_path ) ), esc_html( wp_get_current_user()->display_name ) ) );
		$instance::update(
			$entry_id,
			[
				'logs' => $instance->get_logs(),
			]
		);
		wp_send_json_success();
	}

	/**
	 * Provides the markup for the entry edit button.
	 *
	 * @since 1.3.0
	 * @return void
	 */
	public function edit_entry_button_markup() {
		if ( ! isset( $_GET['entry_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is skipped here as we don't get nonce in the URL here.
			return;
		}

		?>
		<button class="button button-link srfm-edit-entry" type="button">
			<?php Pro_Helper::print_pro_icon( 'edit' ); ?>
			<?php esc_html_e( 'Edit', 'sureforms-pro' ); ?>
		</button>
		<?php
	}

	/**
	 * Provides the markup for the edit entry dialog box.
	 *
	 * @param array<string,mixed> $entry The entry data.
	 * @since 1.3.0
	 * @return void
	 */
	public function edit_entry_dialog_markup( $entry ) {
		if ( empty( $entry['ID'] ) ) {
			return;
		}

		$post     = get_post( absint( $entry['form_id'] ) );
		$entry_id = absint( $entry['ID'] );
		$blocks   = self::prepare_editing_blocks( $post, $entry );

		?>
		<dialog id="srfm-edit-entry-modal">
			<div class="srfm-edit-entry-modal-container">
				<div class="edit-entry-header padding-left-right">
					<h2><?php esc_html_e( 'Edit Entry Data', 'sureforms-pro' ); ?></h2>
					<button type="button" class="srfm-cancel-entry-btn">
						<?php Pro_Helper::print_pro_icon( 'close' ); ?>
					</button>
				</div>
				<div class="edit-entry-content padding-left-right">
					<?php
					if ( ! empty( $blocks ) && is_array( $blocks ) ) {
						foreach ( $blocks as $block ) {

							if ( ! isset( $block['blockName'] ) ) {
								continue;
							}

							$args = [
								'block_name'    => $block['blockName'],
								'entry'         => $entry,
								'all_blocks'    => $blocks,
								'current_block' => $block,
							];

							/**
							 * Filter to determine if a block should be skipped during entry editing.
							 *
							 * Some blocks like repeater fields are processed by their respective packages,
							 * so we skip rendering them here and let the package handle the template rendering.
							 *
							 * @since 1.11.0
							 * @param bool  $should_skip_block Whether to skip rendering this block
							 * @param array $args {
							 *     Arguments passed to the filter.
							 *     @type string $block_name    The name of the block
							 *     @type array  $entry         The entry data
							 *     @type array  $all_blocks    All blocks in the form
							 *     @type array  $current_block Current block being processed
							 * }
							 */
							$should_skip_block_on_entry = apply_filters( 'srfm_should_skip_block_from_edit_entry', false, $args );

							/**
							 * Action to process and render a block during entry editing.
							 *
							 * Allows packages to handle rendering their own block templates.
							 * For example, the repeater package uses this to render its template.
							 *
							 * @since 1.11.0
							 * @param array $args {
							 *     Arguments passed to the action.
							 *     @type string $block_name    The name of the block
							 *     @type array  $entry         The entry data
							 *     @type array  $all_blocks    All blocks in the form
							 *     @type array  $current_block Current block being processed
							 * }
							 */
							do_action( 'srfm_process_block_on_edit_entry', $args );

							if ( $should_skip_block_on_entry ) {
								continue;
							}

							echo render_block( $block ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- We need to print the form blocks markup.
						}
					}
					?>
				</div>
				<div class="edit-entry-footer padding-left-right">
					<?php wp_nonce_field( 'srfm-edit-entry-' . $entry_id, 'srfm-edit-entry-nonce' ); ?>
					<input type="hidden" name="entry_id" value="<?php echo absint( $entry_id ); ?>">
					<input class="button button-primary srfm-update-entry-btn" type="submit" value="<?php esc_attr_e( 'Update Entry', 'sureforms-pro' ); ?>">
					<button type="button" class="button button-secondary srfm-cancel-entry-btn"><?php esc_html_e( 'Cancel', 'sureforms-pro' ); ?></button>
				</div>
			</div>
		</dialog>
		<?php
	}

	/**
	 * Render the entry logs for a specific entry.
	 *
	 * @since 1.3.0
	 * @return string|false Entry logs markup.
	 */
	public function render_entry_logs() {
		ob_start();
		?>
		<div id="sureform_entry_meta" class="postbox srfm-entry-logs">
			<div class="in-progress-overlay">
				<?php Pro_Helper::print_pro_icon( 'overlaySpinner' ); ?>
			</div>
			<div class="postbox-header">
				<!-- Removed "hndle ui-sortable-handle" class from h2 to remove the draggable stylings. -->
				<h2><?php esc_html_e( 'Entry Logs', 'sureforms-pro' ); ?></h2>
			</div>
			<div class="inside">
				<?php // We will populate this div using AJAX. ?>
			</div>
			<div class="entry-navigation-btn-wrapper">
				<button type="button" class="entry-navigation-btn entry-logs-navigation-btn" data-type="prev">
					<?php Pro_Helper::print_pro_icon( 'previous' ); ?>
					<span>
						<?php esc_html_e( 'Previous', 'sureforms-pro' ); ?>
					</span>
				</button>
				<button type="button" class="entry-navigation-btn entry-logs-navigation-btn" data-type="next">
					<span>
						<?php esc_html_e( 'Next', 'sureforms-pro' ); ?>
					</span>
					<?php Pro_Helper::print_pro_icon( 'next' ); ?>
				</button>
			</div>
		</div>
		<?php
		return ob_get_clean();
	}

	/**
	 * Provides markup for the entry notes.
	 *
	 * @param array<string,mixed> $entry The entry data.
	 * @since 1.3.0
	 * @return void
	 */
	public function edit_entry_notes_markup( $entry ) {
		if ( empty( $entry['ID'] ) ) {
			return;
		}

		$entry_id = absint( $entry['ID'] );
		$notes    = $entry['notes'];
		?>
		<div id="submitdiv" class="postbox entry-notes">
			<div class="in-progress-overlay">
				<?php Pro_Helper::print_pro_icon( 'overlaySpinner' ); ?>
			</div>
			<div class="postbox-header">
				<h2><?php esc_html_e( 'Entry Notes', 'sureforms-pro' ); ?></h2>
				<button type="button" id="srfm-add-entry-note" class="srfm-add-entry-note-button">
					<?php esc_html_e( 'Add Note', 'sureforms-pro' ); ?>
					<?php Pro_Helper::print_pro_icon( 'addNotePlus' ); ?>
				</button>
			</div>
			<div class="inside">
				<div class="srfm-entry-note-wrapper">
					<div class="entry-notes-container">
						<?php // We will populate this div using AJAX. ?>
					</div>
					<div class="add-notes-field <?php echo ! empty( $notes ) ? 'hidden' : ''; ?>">
						<textarea id="srfm-entry-note" rows="5"></textarea>
						<button id="srfm-add-note" type="submit" class="button" data-entry-id=<?php echo absint( $entry_id ); ?>><?php esc_html_e( 'Submit Note', 'sureforms-pro' ); ?></button>
					</div>
				</div>
			</div>

			<div class="entry-navigation-btn-wrapper">
				<button type="button" class="entry-navigation-btn entry-notes-nav-btn" data-type="prev">
					<?php Pro_Helper::print_pro_icon( 'previous' ); ?>
					<span>
						<?php esc_html_e( 'Previous', 'sureforms-pro' ); ?>
					</span>
				</button>
				<button type="button" class="entry-navigation-btn entry-notes-nav-btn" data-type="next">
					<span>
						<?php esc_html_e( 'Next', 'sureforms-pro' ); ?>
					</span>
					<?php Pro_Helper::print_pro_icon( 'next' ); ?>
				</button>
			</div>
		</div>
		<?php
	}

	/**
	 * Provides the bulk resend notification button markup.
	 *
	 * @since 1.3.0
	 * @return void
	 */
	public function display_bulk_resend_notification_button() {
		if ( isset( $_GET['form_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here.
			$form_id = absint( wp_unslash( $_GET['form_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here.
		}
		if ( ! isset( $form_id ) ) {
			// Do not display resend notification button if a form is not selected or form_id is not set.
			return;
		}

		$this->resend_notification_markup( $form_id );
	}

	/**
	 * Provides the markup for the resend notification button in edit entry page.
	 *
	 * @param array<string,mixed> $entry The entry data.
	 * @since 1.3.0
	 * @return void
	 */
	public function edit_entry_resend_notification_button( $entry ) {
		if ( empty( $entry['ID'] ) ) {
			return;
		}

		$entry_id = absint( $entry['ID'] );
		$form_id  = absint( $entry['form_id'] );

		$this->resend_notification_markup( $form_id, [ $entry_id ] );
	}

	/**
	 * Display resend notification modal markup.
	 *
	 * @param int        $form_id Form ID.
	 * @param array<int> $entry_ids An array of entry ids.
	 * @since 1.3.0
	 * @return void
	 */
	public function resend_notification_markup( $form_id, $entry_ids = [] ) {
		if ( ! $form_id ) {
			return;
		}

		/**
		 * Get email notifications for the form.
		 *
		 * @var array<array<string,string>> $email_notifications
		 */
		$email_notifications = Helper::get_array_value( get_post_meta( $form_id, '_srfm_email_notification', true ) );
		?>
		<button type="button" class="button <?php echo empty( $entry_ids ) ? 'hidden' : ''; ?> srfm-resend-notification-trigger-btn"><?php esc_html_e( 'Resend Notification', 'sureforms-pro' ); ?></button>
		<dialog id="srfm-resend-notification-modal">
			<div class="in-progress-overlay hidden">
				<?php Pro_Helper::print_pro_icon( 'overlaySpinner' ); ?>
			</div>
			<div class="modal-title">
				<h3><?php esc_html_e( 'Resend Notification', 'sureforms-pro' ); ?></h3>
			</div>
			<?php
			if ( empty( $email_notifications ) ) {
				?>
				<div class="modal-content">
					<p>
					<?php
					/* translators: %s is the form name. */
					printf( esc_html__( 'No email notifications found for the "%s" form. You can create email notification from the form edit page.', 'sureforms-pro' ), esc_html( get_the_title( $form_id ) ) );
					?>
					</p>
				</div>
				<div class="modal-actions">
					<button type="button" class="button srfm-cancel-resend-notification"><?php esc_html_e( 'Okay', 'sureforms-pro' ); ?></button>
				</div>
				<?php
			} else {
				$enabled_email_notifications = self::get_enabled_email_notifications( $email_notifications );

				if ( empty( $enabled_email_notifications ) ) {
					?>
					<div class="modal-content">
						<p>
						<?php
						/* translators: %s is the form name. */
						printf( esc_html__( 'No email notifications enabled for the "%s" form. You can enable email notification from the form edit page.', 'sureforms-pro' ), esc_html( get_the_title( $form_id ) ) );
						?>
						</p>
					</div>
					<div class="modal-actions">
						<button type="button" class="button srfm-cancel-resend-notification"><?php esc_html_e( 'Okay', 'sureforms-pro' ); ?></button>
					</div>
					<?php
				} else {
					?>
					<div class="modal-content">
						<div class="field-group">
							<h4><?php esc_html_e( 'Notification', 'sureforms-pro' ); ?></h4>
							<select name="email_notification" class="srfm-resend-notification-field">
								<?php
								foreach ( $enabled_email_notifications as $email_notification ) {
									?>
									<option value="<?php echo esc_attr( $email_notification['id'] ); ?>"><?php echo esc_html( $email_notification['name'] ); ?></option>
									<?php
								}
								?>
							</select>
						</div>

						<div class="field-group">
							<h4><?php esc_html_e( 'Send To', 'sureforms-pro' ); ?></h4>
							<select name="send_to" class="srfm-resend-notification-field">
								<option value="default"><?php esc_html_e( 'Default', 'sureforms-pro' ); ?></option>
								<option value="other"><?php esc_html_e( 'Other', 'sureforms-pro' ); ?></option>
							</select>
						</div>

						<div class="field-group recipient-field-group hidden">
							<h4><?php esc_html_e( 'Recipient Email', 'sureforms-pro' ); ?></h4>
							<input type="email" name="recipient" class="srfm-resend-notification-field">
						</div>

						<input type="hidden" name="form_id" value="<?php echo absint( $form_id ); ?>" class="srfm-resend-notification-field">

						<!-- We will populate this field using JS for bulk resend -->
						<input type="hidden" name="entry_ids" value="<?php echo esc_attr( implode( ',', $entry_ids ) ); ?>" class="srfm-resend-notification-field">
					</div>
					<div class="modal-actions">
						<button type="button" class="button button-primary srfm-resend-notification"><?php esc_html_e( 'Resend Notification', 'sureforms-pro' ); ?></button>
						<button type="button" class="button srfm-cancel-resend-notification"><?php esc_html_e( 'Cancel', 'sureforms-pro' ); ?></button>
					</div>
					<?php
				}
			}
			?>
		</dialog>
		<?php
	}

	/**
	 * Filters the email notifications to only include those that are enabled.
	 *
	 * @param array<array<string,string>> $email_notifications The email notifications to filter.
	 * @since 1.7.1
	 * @return array<array<string,string>>
	 */
	public static function get_enabled_email_notifications( $email_notifications ) {

		foreach ( $email_notifications as $key => $email_notification ) {
			if ( ! isset( $email_notification['status'] ) || true !== $email_notification['status'] ) {
				unset( $email_notifications[ $key ] );
			}
		}

		return $email_notifications;
	}

	/**
	 * Helper method to paginate the provided array data.
	 *
	 * @param array<mixed> $array Array item to paginate.
	 * @param int          $current_page Current page number.
	 * @param int          $items_per_page Total items to return per pagination.
	 * @since 1.3.0
	 * @return array<mixed>
	 */
	public static function paginate_array( $array, $current_page, $items_per_page = 3 ) {
		$total_items = count( $array );
		$total_pages = Helper::get_integer_value( ceil( $total_items / $items_per_page ) );

		// Ensure current page is within bounds.
		$current_page = max( 1, min( $total_pages, $current_page ) );

		// Calculate the offset for slicing.
		$offset = ( $current_page - 1 ) * $items_per_page;

		// Get the items for the current page.
		$items = array_slice( $array, $offset, $items_per_page, true );

		// Determine the next and previous page numbers.
		$next_page = $current_page < $total_pages ? $current_page + 1 : false;
		$prev_page = $current_page > 1 ? $current_page - 1 : false;

		return compact(
			'items',
			'offset',
			'next_page',
			'prev_page',
			'total_items',
			'total_pages',
			'current_page',
		);
	}

	/**
	 * Prepares the form blocks for entry editing mode.
	 *
	 * @param \WP_Post|null $post The post object.
	 * @param array<mixed>  $entry The entry data.
	 * @since 1.3.0
	 * @return array
	 */
	public static function prepare_editing_blocks( $post, $entry ) {
		if ( ! $post || ! is_object( $post ) ) {
			return [];
		}

		$parsed_blocks = parse_blocks( $post->post_content );

		if ( ! is_array( $parsed_blocks ) ) {
			return [];
		}

		if ( ! empty( $parsed_blocks ) && is_array( $parsed_blocks ) ) {
			foreach ( $parsed_blocks as &$parsed_block ) {
				self::prepare_editing_blocks_attrs( $parsed_block, $entry );
			}
		}

		return $parsed_blocks;
	}

	/**
	 * Before deleting the entry.
	 *
	 * @param int $entry_id The ID of the entry to delete.
	 *
	 * @since 1.8.0
	 * @return void
	 */
	public function before_delete_entry( $entry_id ) {
		$entry = Entries::get_entry_data( $entry_id );
		if ( empty( $entry ) ) {
			return;
		}

		// Do action to delete the entry files.
		do_action( 'srfm_pro_before_deleting_entry', $entry );
	}

	/**
	 * Returns the error message based on the error type.
	 *
	 * @param string $type The error type.
	 * @since 1.3.0
	 * @return string
	 */
	protected function get_error_msg( $type ) {
		$messages = [
			'permission' => __( 'You do not have permission to perform this action.', 'sureforms-pro' ),
			'invalid'    => __( 'Invalid request.', 'sureforms-pro' ),
			'nonce'      => __( 'Nonce verification failed.', 'sureforms-pro' ),
		];

		return $messages[ $type ] ?? '';
	}

	/**
	 * Helper method to validate the entry request.
	 *
	 * This method checks if the user has permission to manage options and
	 * if the entry ID is provided in the POST request. It then returns the
	 * sanitized entry ID.
	 *
	 * @since 1.3.0
	 * @return int
	 */
	protected function validate_entry_request() {
		if ( ! Helper::current_user_can() ) {
			wp_send_json_error( [ 'message' => $this->get_error_msg( 'permission' ) ] );
		}

		if ( empty( $_POST['entryID'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- We are checking nonce in the necessary methods.
			wp_send_json_error( [ 'message' => $this->get_error_msg( 'invalid' ) ] );
		}

		return absint( wp_unslash( $_POST['entryID'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- We are checking nonce in the necessary methods.
	}

	/**
	 * Provides table markup for the entry logs.
	 *
	 * @param array<array<mixed>> $entry_logs Entry logs stored in the database.
	 * @since 1.3.0
	 * @return void
	 */
	protected function entry_logs_table_markup( $entry_logs ) {
		if ( empty( $entry_logs ) ) {
			?>
			<p class="no-logs-found"><?php esc_html_e( 'No logs found for this entry.', 'sureforms-pro' ); ?></p>
			<?php
			return; // Bail early if entry not found.
		}
		?>
		<table class="striped entry-logs-table">
			<tbody>
				<?php foreach ( $entry_logs as $key => $log ) { ?>
					<tr>
						<td class="entry-log-container">
							<div class="entry-log">
								<div class="info-wrap">
									<h4 class="entry-log-title">
										<?php echo esc_html( Helper::get_string_value( $log['title'] ) ); ?>
										<?php echo esc_html( gmdate( '\a\t Y-m-d h:i:s A', absint( $log['timestamp'] ) ) ); ?>
									</h4>
									<div class="entry-log-messages">
									<?php
									if ( ! empty( $log['messages'] ) && is_array( $log['messages'] ) ) {
										foreach ( $log['messages'] as $message ) {
											?>
											<p><?php echo wp_kses_post( $message ); ?></p>
											<?php
										}
									}
									?>
									</div>
								</div>
								<button type="button" class="btn-delete-log" data-log-key="<?php echo esc_attr( $key ); ?>">
									<?php Pro_Helper::print_pro_icon( 'delete' ); ?>
								</button>
							</div>
						</td>
					</tr>
				<?php } ?>
			</tbody>
		</table>
		<?php
	}

	/**
	 * Returns resend email notification alert content.
	 *
	 * @param string $message Message to print in the alert box.
	 * @param bool   $is_success Whether or not is resend email succeed.
	 * @since 1.3.0
	 * @return string Email notification alert box html content with message.
	 */
	protected function resend_email_notifications_alert( $message, $is_success = true ) {
		ob_start();
		?>
		<div class="srfm-resend-notification-message">
			<div class="icon">
				<?php
				if ( $is_success ) {
					Pro_Helper::print_pro_icon( 'resendNotificationSuccess' );
				} else {
					Pro_Helper::print_pro_icon( 'resendNotificationFailed' );
				}
				?>
			</div>
			<div class="message">
				<?php if ( $is_success ) { ?>
					<h4><?php esc_html_e( 'Email Notification Initialized', 'sureforms-pro' ); ?></h4>
				<?php } else { ?>
					<h4><?php esc_html_e( 'Error', 'sureforms-pro' ); ?></h4>
				<?php } ?>
				<p><?php echo esc_html( $message ); ?></p>
			</div>
			<button type="button" class="close">
				<?php Pro_Helper::print_pro_icon( 'close' ); ?>
			</button>
		</div>
		<?php
		$content = ob_get_clean();
		return is_string( $content ) ? $content : '';
	}

	/**
	 * Prepares the form blocks for entry editing mode.
	 *
	 * @param array<array<mixed>> $block The block data.
	 * @param array<mixed>        $entry The entry data.
	 * @since 1.3.0
	 * @return void
	 */
	protected static function prepare_editing_blocks_attrs( &$block, $entry ) {
		if ( ! $block['blockName'] ) {
			return;
		}

		if ( empty( $block['attrs']['slug'] ) ) {
			// If we don't have slug then this is invalid block for editing purpose.
			$block['blockName'] = null;
			return;
		}

		$block['attrs']['entryID']   = absint( $entry['ID'] );
		$block['attrs']['isEditing'] = true;

		if ( ! empty( $block['innerBlocks'] ) ) {
			foreach ( $block['innerBlocks'] as &$inner_block ) {
				self::prepare_editing_blocks_attrs( $inner_block, $entry );
			}
			return;
		}

		if ( ! empty( $entry['form_data'] ) && is_array( $entry['form_data'] ) ) {
			foreach ( $entry['form_data'] as $field_name => $value ) {
				if ( false !== strpos( $field_name, "-{$block['attrs']['block_id']}-" ) ) {
					$block['attrs']['fieldName']    = $field_name;
					$block['attrs']['defaultValue'] = $value;
					break;
				}
			}
		}
	}

	/**
	 * Prints entry note item markup.
	 *
	 * @param array<mixed> $note Single note array.
	 * @since 1.3.0
	 * @return void
	 */
	protected function entry_note_item_markup( $note ) {
		$user              = get_user_by( 'ID', absint( $note['submitted_by'] ) );
		$submitted_by_user = $user ? $user->display_name : __( 'Unknown User', 'sureforms-pro' );
		$note_full         = wp_kses_post( Helper::get_string_value( $note['note'] ) );
		$note_word_count   = str_word_count( wp_strip_all_tags( $note_full ) );
		?>
		<div class="entry-note-item">
			<div class="srfm-entry-note-header">
				<span>
					<strong class="entry-log-title">
						<?php
							/* translators: Here %s means the users display name. */
							printf( esc_html__( 'Submitted by %s', 'sureforms-pro' ), esc_html( $submitted_by_user ) );
						?>
					</strong>
					<br/>
					<small><?php echo esc_html( gmdate( 'Y-m-d h:i:s A', Helper::get_integer_value( $note['timestamp'] ) ) ); ?></small>
				</span>
				<button data-note-key="<?php echo esc_attr( Helper::get_string_value( $note['timestamp'] ) ); ?>" type="button" class="btn-delete-note">
					<?php Pro_Helper::print_pro_icon( 'delete' ); ?>
				</button>
			</div>
			<div class="srfm-entry-note-content">
				<?php if ( $note_word_count < 15 ) { ?>
					<div class="srfm-note-full">
						<p><?php echo wp_kses_post( $note_full ); ?></p>
					</div>
				<?php } else { ?>
					<div class="srfm-note-excerpt">
						<p>
							<?php echo wp_kses_post( wp_trim_words( $note_full, 10 ) ); ?>
							<button class="srfm-note-visibility srfm-btn-show"><?php esc_html_e( 'Show More', 'sureforms-pro' ); ?></button>
						</p>
					</div>
					<div class="srfm-note-full hidden">
						<p>
							<?php echo wp_kses_post( $note_full ); ?>
							<button class="srfm-note-visibility srfm-btn-hide"><?php esc_html_e( 'Show Less', 'sureforms-pro' ); ?></button>
						</p>
					</div>
				<?php } ?>
			</div>
		</div>
		<?php
	}
}
