<?php
/**
 * The public-facing functionality of the plugin.
 *
 * Defines the plugin name, version, and two examples hooks for how to
 * enqueue the public-facing stylesheet and JavaScript.
 *
 * @package    inline-comments-for-post
 * @subpackage inline-comments-for-post/public
 * @author     Multidots <info@multidots.com>
 */

declare( strict_types = 1 );

namespace INLINE_COMMENTS_FOR_POST\Includes;

use INLINE_COMMENTS_FOR_POST\Includes\Traits\Singleton;

/**
 * Frontend main class.
 */
class Front {


	use Singleton;

	/**
	 * The ID of this plugin.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @var      string    $plugin_name    The ID of this plugin.
	 */
	private $plugin_name;

	/**
	 * The version of this plugin.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @var      string    $version    The current version of this plugin.
	 */
	private $version;

	/**
	 * The comment settings of this plugin.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @var      array    $icfp_comment_settings    The comment settings of this plugin.
	 */
	private $icfp_comment_settings;

	/**
	 * Flag to track when we're rendering post content (inside .entry-content or .wp-block-post-content).
	 * Used to limit block attribute wrapping to only post content blocks.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @var      bool    $is_rendering_post_content    Whether we're currently rendering post content.
	 */
	private static $is_rendering_post_content = false;

	/**
	 * Initialize the class and set its properties.
	 *
	 * @since    1.0.0
	 */
	public function __construct() {
		if ( defined( 'INLINE_COMMENTS_FOR_POST_VERSION' ) ) {
			$this->version = INLINE_COMMENTS_FOR_POST_VERSION;
		} else {
			$this->version = '1.0.2';
		}
		$this->setup_front_hooks();
	}

	/**
	 * All public facing hook will be placed under this function.
	 *
	 * @return void
	 */
	public function setup_front_hooks(): void {
		add_action( 'wp_enqueue_scripts', array( $this, 'icfp_enqueue_styles' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'icfp_enqueue_scripts' ) );

		add_action( 'enqueue_block_assets', array( $this, 'icfp_enqueue_editor_assets' ) );
		add_filter( 'script_loader_tag', array( $this, 'icfp_script_additional_attrs' ), 10, 2 );
		add_filter( 'should_load_separate_core_block_assets', '__return_true' );

		add_action( 'wp_footer', array( $this, 'icfp_public_footer' ) );
		add_action( 'register_block_type_args', array( $this, 'icfp_replace_default_comment_block' ), 99, 2 );

		add_action( 'wp_ajax_nopriv_icfp_add_front_comment', array( $this, 'icfp_add_front_comment_function' ) );
		add_action( 'wp_ajax_icfp_add_front_comment', array( $this, 'icfp_add_front_comment_function' ) );

		add_action( 'wp_ajax_nopriv_icfp_get_comment', array( $this, 'icfp_get_comment_function' ) );
		add_action( 'wp_ajax_icfp_get_comment', array( $this, 'icfp_get_comment_function' ) );

		add_action( 'wp_ajax_nopriv_icfp_check_duplicate_comment', array( $this, 'icfp_check_duplicate_comment_function' ) );
		add_action( 'wp_ajax_icfp_check_duplicate_comment', array( $this, 'icfp_check_duplicate_comment_function' ) );

		add_action( 'wp_ajax_nopriv_icfp_get_comment_marks', array( $this, 'icfp_get_comment_marks_function' ) );
		add_action( 'wp_ajax_icfp_get_comment_marks', array( $this, 'icfp_get_comment_marks_function' ) );

		add_filter( 'the_content', array( $this, 'icfp_render_comment_template_before_content' ) );
		add_filter( 'comment_reply_link', array( $this, 'icfp_custom_reply_link' ), 10, 4 );

		$this->icfp_comment_settings = get_option( 'icfp_comment_settings' ) ?? array();
	}


	/**
	 * Register the stylesheets for the public-facing side of the site.
	 *
	 * @return void
	 * @since    1.0.0
	 */
	public function icfp_enqueue_styles(): void {

		if( ! is_admin() ) {
			$link_theme_color = $this->icfp_comment_settings['icfp_comment_color'] ?? '#4b1bce';

			wp_register_style( 'inline-comments-for-post-front-inline', false );
			wp_enqueue_style( 'inline-comments-for-post-front-inline' );

			wp_add_inline_style(
				'inline-comments-for-post-front-inline',
				'* { --link-theme-color: ' . esc_attr( $link_theme_color ) . '; }'
			);

			wp_enqueue_style( 'inline-comments-for-post-front', INLINE_COMMENTS_FOR_POST_URL . 'assets/build/main.css', array(), $this->version, 'all' );
		}
	}

	/**
	 * Register the JavaScript for the public-facing side of the site.
	 *
	 * @return void
	 * @since    1.0.0
	 */
	public function icfp_enqueue_scripts(): void {

		if( ! is_admin() ) {
			wp_enqueue_script( 'inline-comments-for-post', trailingslashit( INLINE_COMMENTS_FOR_POST_URL ) . 'assets/src/js/frontend/index.js', array( 'jquery', 'wp-blocks', 'wp-editor' ), wp_rand(), false );

			wp_enqueue_script( 'comment-reply' );

			wp_localize_script(
				'inline-comments-for-post',
				'siteConfig',
				array(
					'ajaxUrl'    => admin_url( 'admin-ajax.php' ),
					'ajax_nonce' => wp_create_nonce( 'loadmore_post_nonce' ),
				)
			);

			// Ensure the function exists
			if ( ! function_exists( 'is_plugin_active' ) ) {
				include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
			}

			// Check if Elementor plugin is active
			if ( is_plugin_active( 'elementor/elementor.php' ) ) {
				wp_enqueue_script( 'board-front-elementor', trailingslashit( INLINE_COMMENTS_FOR_POST_URL ) . 'assets/src/js/frontend/elementor.js', array( 'jquery', 'wp-blocks', 'wp-editor', 'comment-reply' ), wp_rand(), false );
			} else {
				wp_enqueue_script( 'board-front-function', trailingslashit( INLINE_COMMENTS_FOR_POST_URL ) . 'assets/src/js/frontend/frontFunction.js', array( 'jquery', 'wp-blocks', 'wp-editor' ), wp_rand(), false );
			}

			wp_localize_script( 'inline-comments-for-post', 'cf_public_localizer', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
			wp_localize_script( 'inline-comments-for-post', 'cf_public_nonce', array( 'nonce'=>  wp_create_nonce( 'cf_public_nonce' ) ) );

		}
	}

	/**
	 * Wraps rendered blocks on the front-end with additional attributes that
	 * expose block metadata (id, name, attrs) to JavaScript.
	 *
	 * This allows the React front-end logic to reliably target and identify
	 * individual blocks when working with inline comments.
	 *
	 * @param string $block_content Rendered block HTML.
	 * @param array  $block         Parsed block data.
	 *
	 * @return string
	 */
	public function icfp_wrap_front_block_with_attrs( string $block_content, array $block ): string {

		if ( is_admin() || '' === trim( $block_content ) ) {
			return $block_content;
		}

		// Only apply block attributes inside .entry-content or .wp-block-post-content sections.
		// This prevents wrapping blocks in widgets, sidebars, headers, footers, etc.
		// Check if we're on a singular post/page and in the main query (not widgets, etc.).
		// Note: We don't check in_the_loop() because render_block can be called outside
		// the loop context even when rendering post content.
		if ( ! is_singular() || ! is_main_query() ) {
			return $block_content;
		}

		$block_name = $block['blockName'] ?? '';
		if ( '' === $block_name ) {
			return $block_content;
		}

		$block_attrs = $block['attrs'] ?? array();

		// Encode attributes for JS to read.
		$attrs_json = wp_json_encode( $block_attrs );

		$block_id = 'icfp-block-' . wp_generate_uuid4();

		// Instead of wrapping in a div, add attributes directly to the block's root element.
		// This preserves the original HTML structure (e.g., <p>, <h2>, etc.).
		return $this->icfp_add_attributes_to_block_root(
			$block_content,
			array(
				'id'                    => $block_id,
				'data-icfp-block-id'    => $block_id,
				'data-icfp-block-name'  => $block_name,
				'data-icfp-block-attrs' => $attrs_json,
			)
		);
	}

	/**
	 * Inject mark elements into blocks server-side at render time.
	 * This ensures marks are in the HTML from the start, no JavaScript restoration needed.
	 * This runs at the block level, so we can match blocks by name and attrs instead of ID.
	 *
	 * @param string $block_content The rendered block HTML.
	 * @param array  $block         The parsed block data.
	 * @return string Modified block content with marks injected.
	 */
	public function icfp_inject_marks_into_block( string $block_content, array $block ): string {
		// Only process on singular posts/pages
		if ( is_admin() || ! is_singular() || ! is_main_query() || '' === trim( $block_content ) ) {
			return $block_content;
		}

		global $post;
		if ( ! $post || ! isset( $post->ID ) ) {
			return $block_content;
		}

		$block_name = $block['blockName'] ?? '';
		$block_attrs = $block['attrs'] ?? array();

		// Get all approved comments for this post
		$args = array(
			'post_id' => $post->ID,
			'status'  => array( 'approve', 'hold' ), // Include pending comments too
			'number'  => 999999,
		);

		$comments = get_comments( $args );
		if ( empty( $comments ) ) {
			return $block_content;
		}

		// Process comments in reverse order (newest first) to avoid offset issues
		$comments = array_reverse( $comments );

		foreach ( $comments as $comment ) {
			$comment_meta = get_comment_meta( $comment->comment_ID, 'cf_front_comment_meta', true );
			if ( empty( $comment_meta ) ) {
				continue;
			}

			$comment_meta_array = json_decode( $comment_meta, true );
			if ( ! is_array( $comment_meta_array ) || empty( $comment_meta_array['comment_on_text'] ) ) {
				continue;
			}

			$comment_text = $comment_meta_array['comment_on_text'];
			$datatext     = $comment_meta_array['datatext'] ?? '';
			$stored_block_name   = $comment_meta_array['block_name'] ?? '';
			$stored_block_attrs_raw = $comment_meta_array['block_attrs'] ?? array();
			// Decode block_attrs if it's a JSON string
			if ( is_string( $stored_block_attrs_raw ) ) {
				$stored_block_attrs = json_decode( $stored_block_attrs_raw, true );
				if ( ! is_array( $stored_block_attrs ) ) {
					$stored_block_attrs = array();
				}
			} else {
				$stored_block_attrs = is_array( $stored_block_attrs_raw ) ? $stored_block_attrs_raw : array();
			}
			$highlight_id = $comment_meta_array['highlight_id'] ?? 'icfp-highlight-' . $comment->comment_ID;

			// Skip if no datatext and no comment ID
			if ( empty( $datatext ) && empty( $comment->comment_ID ) ) {
				continue;
			}

			// Check if mark already exists in this block (avoid duplicates)
			$mark_pattern = '/<mark[^>]*data-icfp-highlight-id="' . preg_quote( esc_attr( $highlight_id ), '/' ) . '"[^>]*>/i';
			if ( preg_match( $mark_pattern, $block_content ) ) {
				continue; // Mark already exists, skip
			}

			// Match blocks by block_name and block_attrs (since block_id is regenerated on each page load)
			$block_matches = false;
			
			// First, check if block_name matches
			if ( ! empty( $stored_block_name ) && $stored_block_name === $block_name ) {
				// If block_attrs are stored, compare them
				if ( ! empty( $stored_block_attrs ) && is_array( $stored_block_attrs ) ) {
					// Compare block attributes (only check keys that exist in stored attrs)
					$attrs_match = true;
					foreach ( $stored_block_attrs as $key => $value ) {
						if ( ! isset( $block_attrs[ $key ] ) || $block_attrs[ $key ] !== $value ) {
							$attrs_match = false;
							break;
						}
					}
					if ( $attrs_match ) {
						$block_matches = true;
					}
				} else {
					// No stored attrs, just match by name
					$block_matches = true;
				}
			}

			// If block doesn't match, skip this comment
			if ( ! $block_matches ) {
				continue;
			}

			// Clean the comment text for matching (strip HTML tags, normalize whitespace)
			$clean_comment_text = wp_strip_all_tags( $comment_text );
			$clean_comment_text = preg_replace( '/\s+/', ' ', $clean_comment_text );
			$clean_comment_text = trim( $clean_comment_text );

			// Strip HTML from block content for text matching
			$clean_block_content = wp_strip_all_tags( $block_content );
			$clean_block_content = preg_replace( '/\s+/', ' ', $clean_block_content );

			// Check if the comment text exists in this block
			if ( stripos( $clean_block_content, $clean_comment_text ) === false ) {
				continue; // Text not found in this block
			}
			
			// CRITICAL: When multiple blocks have same name and empty attrs, we need to identify the correct block
			// Use a global tracker to prevent injecting the same mark into multiple blocks
			global $icfp_injected_marks;
			if ( ! isset( $icfp_injected_marks ) ) {
				$icfp_injected_marks = array();
			}
			
			// Check if this mark was already injected in a previous block (by datatext or highlight_id)
			$mark_key = $datatext . '_' . $highlight_id;
			if ( isset( $icfp_injected_marks[ $mark_key ] ) ) {
				// Mark already injected in another block, skip this block
				continue;
			}
			
			// For blocks with same name and empty attrs, use surrounding text context to identify correct block
			// Get surrounding text context from comment meta (if stored)
			$surrounding_text = $comment_meta_array['surrounding_text'] ?? '';
			
			// Escape the comment text for regex, handling HTML entities
			$comment_text_escaped = htmlspecialchars( $comment_text, ENT_QUOTES, 'UTF-8' );
			$escaped_text = preg_quote( $comment_text_escaped, '/' );
			// Normalize whitespace for matching (handle both spaces and HTML entities)
			$escaped_text = preg_replace( '/\s+/', '[\s&nbsp;]+', $escaped_text );

			// Try to find the text in the block content
			$pattern = '/' . $escaped_text . '/iu';
			
			// Find all occurrences of the text in this block
			$matches = array();
			preg_match_all( $pattern, $block_content, $matches, PREG_OFFSET_CAPTURE );
			
			if ( ! empty( $matches[0] ) ) {
				// If we have surrounding text context, use it to find the correct occurrence
				$selected_match = null;
				
				if ( ! empty( $surrounding_text ) ) {
					// Try to find the occurrence that matches the surrounding text context
					foreach ( $matches[0] as $match ) {
						$match_pos = $match[1];
						$match_text = $match[0];
						
						// Get text before and after the match (surrounding context)
						$before_text = substr( $block_content, max( 0, $match_pos - 50 ), 50 );
						$after_text = substr( $block_content, $match_pos + strlen( $match_text ), 50 );
						
						$clean_before = wp_strip_all_tags( $before_text );
						$clean_after = wp_strip_all_tags( $after_text );
						$clean_surrounding = wp_strip_all_tags( $surrounding_text );
						
						// Check if surrounding text matches
						if ( stripos( $clean_before . $match_text . $clean_after, $clean_surrounding ) !== false ||
						     stripos( $clean_surrounding, $clean_before . $match_text . $clean_after ) !== false ) {
							$selected_match = $match;
							break;
						}
					}
				}
				
				// If no surrounding text match or no surrounding text stored, we need to be careful
				// When multiple blocks have same name and empty attrs, we can't reliably determine
				// which one is correct without additional context.
				if ( ! $selected_match ) {
					// If we have empty block_attrs and no surrounding text, skip server-side injection
					// Let JavaScript handle it on the client side where we have better context
					if ( empty( $stored_block_attrs ) && empty( $surrounding_text ) ) {
						// Skip injection - let client-side JavaScript handle it
						continue;
					}
					// Otherwise, use the first match (assuming this is the only matching block)
					$selected_match = $matches[0][0];
				}
				
				if ( $selected_match ) {
					$match_text = $selected_match[0];
					$match_pos = $selected_match[1];
					
					// Build the mark element with all attributes
					// Note: We don't add 'mdspan-front-comment' class here - it will be added
					// only when user clicks on a comment from the slider
					$mark_attrs = array(
						'datatext'               => esc_attr( $datatext ?: 'legacy_' . $comment->comment_ID ),
						'id'                     => esc_attr( $highlight_id ),
						'data-icfp-highlight-id' => esc_attr( $highlight_id ),
						'data-comment-id'        => esc_attr( $comment->comment_ID ),
					);

					// Set block_name for reference
					if ( ! empty( $block_name ) ) {
						$mark_attrs['data-icfp-block-name'] = esc_attr( $block_name );
					}

					// Build attributes string
					$attrs_string = '';
					foreach ( $mark_attrs as $attr => $value ) {
						$attrs_string .= ' ' . esc_attr( $attr ) . '="' . esc_attr( $value ) . '"';
					}

					// Wrap the matched text with mark element (replace at specific position)
					$before_match = substr( $block_content, 0, $match_pos );
					$after_match = substr( $block_content, $match_pos + strlen( $match_text ) );
					$replacement = '<mark' . $attrs_string . '>' . $match_text . '</mark>';
					$block_content = $before_match . $replacement . $after_match;
					
					// Mark this as injected to prevent duplicate injection in other blocks
					$icfp_injected_marks[ $mark_key ] = true;
				}
			}
		}

		return $block_content;
	}

	/**
	 * Adds attributes directly to the root element of a block's HTML content,
	 * instead of wrapping it in a new div.
	 *
	 * @param string $block_content The block's HTML content.
	 * @param array  $attributes    Array of attributes to add (key => value).
	 *
	 * @return string Modified block content with attributes added to root element.
	 */
	private function icfp_add_attributes_to_block_root( string $block_content, array $attributes ): string {
		if ( '' === trim( $block_content ) ) {
			return $block_content;
		}

		// Build the attribute string.
		$attr_string = '';
		foreach ( $attributes as $key => $value ) {
			if ( '' !== $value && null !== $value ) {
				$attr_string .= ' ' . $key . '="' . esc_attr( $value ) . '"';
			}
		}

		if ( '' === $attr_string ) {
			return $block_content;
		}

		// Find the first opening tag in the block content.
		// Pattern matches: <tagName ...> or <tagName> (with or without existing attributes).
		if ( preg_match( '/^(\s*<)([a-zA-Z][a-zA-Z0-9]*)(\s[^>]*)?(>)/', $block_content, $matches ) ) {
			// Found an opening tag. Insert attributes after the tag name or before the closing >.
			$before_tag    = $matches[1]; // '<' or whitespace + '<'
			$tag_name      = $matches[2]; // e.g., 'p', 'h2', 'div'
			$existing_attrs = $matches[3] ?? ''; // Existing attributes if any
			$closing_bracket = $matches[4]; // '>'

			// Insert attributes. If there are existing attributes, add after them.
			// Otherwise, add after the tag name.
			if ( trim( $existing_attrs ) !== '' ) {
				// Add after existing attributes, before the closing bracket.
				$modified = $before_tag . $tag_name . $existing_attrs . $attr_string . $closing_bracket;
			} else {
				// Add right after tag name.
				$modified = $before_tag . $tag_name . $attr_string . $closing_bracket;
			}

			// Replace the opening tag in the original content.
			$result = preg_replace( '/^(\s*<)([a-zA-Z][a-zA-Z0-9]*)(\s[^>]*)?(>)/', $modified, $block_content, 1 );

			return $result;
		}

		// If no opening tag found (e.g., just text or comments), wrap in a span as fallback.
		return '<span' . $attr_string . '>' . $block_content . '</span>';
	}

	/**
	 * Enqueue editor scripts and styles.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function icfp_enqueue_editor_assets(): void {
		// Change block Priority to head.
		$blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered();
		foreach ( $blocks as $block ) {
			if ( has_block( $block->name ) ) {
				wp_enqueue_style( $block->style );
			}
		}
	}

	/**
	 * Identify script and do the lazy load.
	 *
	 * @param string $tag Tags string.
	 * @param string $handle Handle name.
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function icfp_script_additional_attrs( string $tag, string $handle ): string {
		if ( 'grs-ad' === $handle ) {
			return str_replace( ' src', ' data-type="lazy" data-src', $tag );
		}

		return $tag;
	}

	/**
 	* Renders the front-end comment UI and loads the comment form.
	*
	* This function is responsible for rendering the comment button and the comment form
	* on the front-end of the website. It creates a toolbar element with a comment button,
	* and then calls the `icfp_front_end_comment_load()` function to load the comment form.
	*
	* @return void
	*/
	public function icfp_public_footer() {
		?>
		<div id="toolbar" class="toolbar" page-id="<?php echo esc_attr( get_the_ID() ) ?>">
			<button type="button" aria-pressed="false" id=":r1a:" data-toolbar-item="true" class="cf_comment_front" aria-label="Comment" data-active-item=""><img src="<?php echo esc_url( INLINE_COMMENTS_FOR_POST_URL ); ?>/assets/images/comment-fl-icon-white.svg" alt=""></button>
		</div>
		<?php
		$this->icfp_front_end_comment_load();
	}

	/**
	* Renders the front-end comment UI and loads the comment form.
	*
	* This function is responsible for rendering the comment button and the comment form
	* on the front-end of the website. It creates a toolbar element with a comment button,
	* and then calls the `icfp_front_end_comment_load()` function to load the comment form.
	*
	* @return void
	*/
 	public function icfp_front_end_comment_load() {
		global $post;
		?>
			<div class="cf-front-comment-wrapper" id="cf_front_comment_wrapper">
				<div class="cf-front-comment-inner-wrapper">
				<div class="cf-front-comment_cancel_wrapper">
					<div id="cf-front-comment-count-inside-slider">
						<span>Responses (<span class="cf-comment-wrapper-count"><?php echo esc_html( get_comment_count( $post->ID )['approved'] ); ?></span>)
						</span>
						<?php //icfp_comment_list_template($comment, $args, $depth); ?>
						</div>
						<img id="cf-front-cancel" src="<?php echo esc_url(INLINE_COMMENTS_FOR_POST_URL); ?>/assets/images/close-icon.svg" alt="cancel">
					</div>
				
					<?php 
						comment_form();
						//add_filter( 'comments_open', '__return_false' );
						?>
						<!-- <div class="cf-sort-comments">
							<label for="cf_sort_comments">Sort by:</label>
							<select name="sort" id="cf_sort_comments">
								<option value="recent" <?php //selected( 'recent', $_GET['sort'] ?? '' ); ?>>Most Recent</option>
								<option value="relevant" <?php //selected( 'relevant', $_GET['sort'] ?? '' ); ?>>Most Relevant</option>
							</select>
						</div> -->
						<div class="cf_front_comment_slider_wrapper" id="cf_front_comment_slider_wrapper" style="display: block;">
					</div>
				</div>
				</div>
		<?php
	}

	/**
	* Renders a single comment in the front-end comment list template.
	*
	* @param WP_Comment $comment The comment object to render.
	* @param array      $args    The arguments for rendering the comment.
	* @param int        $depth   The current depth of the comment in the hierarchy.
	*/
	public function icfp_comment_list_template($comment, $args, $depth) {
    		
		if ( 'div' === $args['style'] ) {
			$tag       = 'div';
			$add_below = 'comment';
		} else {
			$tag       = 'li';
			$add_below = 'div-comment';
		}
		// Manually set classes
		$classes = array('cf-front-comment');
		if ( !empty( $args['has_children'] ) ) {
			$classes[] = 'parent';
		}
		$class_string = join( ' ', $classes );
		?>


		<?php if ( $comment->comment_approved !== '0' ) { ?>

			<<?php echo esc_html( $tag ); ?> class="<?php echo esc_attr( $class_string ); ?>" id="comment-<?php echo esc_attr( $comment->comment_ID ); ?>">
			 <?php
			if ( 'div' != $args['style'] ) { ?>
				<div id="div-comment-<?php esc_attr( $comment->comment_ID ); ?>" class="comment-body" ><?php
			} ?>
			<?php 
			/*if ( $comment->comment_approved == '0' ) { ?>
				<em class="cf-comment_awaiting__moderation"><?php echo esc_html( 'Your comment is awaiting moderation.' ); ?></em><br/><?php 
			}*/ ?>
			<div class="cf-front-comment-main">
				<div class="comment-author cf-front-comment-section"><?php 
					if ( $args['avatar_size'] != 0 ) {
						echo get_avatar( $comment, $args['avatar_size'] ); 
					} 
					?>
				</div>
				<div class="comment-meta commentmetadata">
					<div class="cf-front-comment-date"><?php echo wp_kses_post( get_comment_author_link($comment->comment_ID) ); ?></div>
					<div class="cf-front-comment-time">
						<a href="<?php echo wp_kses_post( get_comment_link( $comment->comment_ID ) ); ?>">
							<?php echo esc_html( $this->icfp_human_readable_comment_time($comment->comment_ID) ); ?>
						</a>
					</div>
				</div>
			</div>
			<?php 
			
			$comment_meta = get_comment_meta( $comment->comment_ID, 'cf_front_comment_meta', true );

			if( isset( $comment_meta ) && !empty( $comment_meta ) ) {
				$comment_meta = json_decode( $comment_meta, true );
				if( isset( $comment_meta['comment_on_text'] ) && !empty( $comment_meta['comment_on_text'] ) ) {
					?>
					<?php
					// Properly decode the comment text, handling Unicode entities
					$display_text = $comment_meta['comment_on_text'];
					// Replace Unicode entity strings (like "u2018", "u2019") with actual characters
					$display_text = preg_replace_callback( '/u([0-9a-fA-F]{4})/', function( $matches ) {
						return mb_convert_encoding( '&#x' . $matches[1] . ';', 'UTF-8', 'HTML-ENTITIES' );
					}, $display_text );
					?>
					<div class="cf-inline-feedback-wrapper" onclick="cfFrontCommentOnClick(this)" data-comment-id="<?php echo esc_attr( $comment->comment_ID ); ?>" data-content="<?php echo esc_attr( $display_text ); ?>">
						<span class="cf-inline-feedback-info">
						<mark class="cf-front-comment-except"><?php echo esc_html( $display_text ); ?></mark>
						</span> 
					</div>
					<?php
				}
			}
			?>
				<div class="cf-front-comment-text-para">
					<?php comment_text($comment->comment_ID); ?>
				</div>
			</div>
			<?php 
			if ( 'div' != $args['style'] ) : ?>
				</div><?php 
			endif;
			?>

		<?php }	
	}

	/**
	* Replaces the default WordPress comment block with a custom comment block.
	*
	* This function is used to override the default WordPress comment block with a custom comment block provided by the "Inline Comments for Post" plugin.
	*
	* @param array  $settings The settings for the comment block.
	* @param string $name     The name of the comment block.
	* @return array The modified settings for the comment block.
	*/
	public function icfp_replace_default_comment_block( $settings, $name ) {

		if ( $name == 'core/comments' ) {
			$settings['render_callback'] = [ &$this, 'cf_render_comment_template' ];
		}

		return $settings;
	}

	/**
 	* Renders the custom comment template for the "Inline Comments for Post" plugin.
	*
	* This function is used to override the default WordPress comment block with a custom comment block provided by the "Inline Comments for Post" plugin. It is called as the render callback for the 'core/comments' block.
	*
	* @param array  $attributes The attributes of the 'core/comments' block.
	* @param string $content    The content of the 'core/comments' block.
	* @param array  $block      The block object for the 'core/comments' block.
	* @return string The rendered custom comment template.
	*/
	public function cf_render_comment_template( $attributes, $content, $block ) {

		ob_start();
        global $post;
		if ( 'open' === $post->comment_status && is_main_query() ) {
			?>
			<div class="cf-front-comment-count_wrap cf-front-comment-bottom">
					<div id="cf-front-comment-count">
						<span>Responses :</span>
						<svg width="24" height="24" viewBox="0 0 24 24" class="jy"><path d="M18 16.8a7.14 7.14 0 0 0 2.24-5.32c0-4.12-3.53-7.48-8.05-7.48C7.67 4 4 7.36 4 11.48c0 4.13 3.67 7.48 8.2 7.48a8.9 8.9 0 0 0 2.38-.32c.23.2.48.39.75.56 1.06.69 2.2 1.04 3.4 1.04.22 0 .4-.11.48-.29a.5.5 0 0 0-.04-.52 6.4 6.4 0 0 1-1.16-2.65v.02zm-3.12 1.06l-.06-.22-.32.1a8 8 0 0 1-2.3.33c-4.03 0-7.3-2.96-7.3-6.59S8.17 4.9 12.2 4.9c4 0 7.1 2.96 7.1 6.6 0 1.8-.6 3.47-2.02 4.72l-.2.16v.26l.02.3a6.74 6.74 0 0 0 .88 2.4 5.27 5.27 0 0 1-2.17-.86c-.28-.17-.72-.38-.94-.59l.01-.02z"></path></svg>
						<span class="cf-comment-count-bottom"><?php echo esc_html( get_comment_count( $post->ID )['approved'] ); ?></span>
					</div>
				</div>
			<?php
			$content = ob_get_clean();
			return $content;
		}

	}

	/**
	 * Prepend a custom comment count template to the content of a single post.
	 *
	 * @param string $content The original content of the post.
	 * @return string The modified content with the comment count template prepended.
	 */
	public function icfp_render_comment_template_before_content($content) {
		// Set flag to indicate we're rendering post content (inside .entry-content or .wp-block-post-content).
		// This allows render_block filter to only apply attributes to blocks within post content.
		self::$is_rendering_post_content = true;

		ob_start();
        global $post;
        ?>
           <div class="cf-front-comment-count_wrap">
                <div id="cf-front-comment-count-top">
                    <span>Responses :</span>
                    <svg width="24" height="24" viewBox="0 0 24 24" class="jy"><path d="M18 16.8a7.14 7.14 0 0 0 2.24-5.32c0-4.12-3.53-7.48-8.05-7.48C7.67 4 4 7.36 4 11.48c0 4.13 3.67 7.48 8.2 7.48a8.9 8.9 0 0 0 2.38-.32c.23.2.48.39.75.56 1.06.69 2.2 1.04 3.4 1.04.22 0 .4-.11.48-.29a.5.5 0 0 0-.04-.52 6.4 6.4 0 0 1-1.16-2.65v.02zm-3.12 1.06l-.06-.22-.32.1a8 8 0 0 1-2.3.33c-4.03 0-7.3-2.96-7.3-6.59S8.17 4.9 12.2 4.9c4 0 7.1 2.96 7.1 6.6 0 1.8-.6 3.47-2.02 4.72l-.2.16v.26l.02.3a6.74 6.74 0 0 0 .88 2.4 5.27 5.27 0 0 1-2.17-.86c-.28-.17-.72-.38-.94-.59l.01-.02z"></path></svg>
					<span class="cf-comment-count-top"><?php echo esc_html( get_comment_count( $post->ID )['approved'] ); ?></span>
                </div>
            </div>
        <?php
        $comment_content = ob_get_clean();


	    // Check if we are on a single post, within the loop, and the main query
	    //if (is_single() && in_the_loop() && is_main_query()) {
		if ( 'open' === $post->comment_status && is_main_query() ) {
	        // Prepend the new div to the content
	        $content = $comment_content . $content;
	    }

		// Reset flag after content is processed.
		self::$is_rendering_post_content = false;

		return $content;
	}

	/**
	 * Inject mark elements into post content server-side.
	 * This ensures marks are in the HTML from the start, no JavaScript restoration needed.
	 *
	 * @param string $content The post content.
	 * @return string Modified content with marks injected.
	 */
	public function icfp_inject_marks_into_content( string $content ): string {
		// Only process on singular posts/pages
		if ( ! is_singular() || ! is_main_query() ) {
			return $content;
		}

		global $post;
		if ( ! $post || ! isset( $post->ID ) ) {
			return $content;
		}

		// Get all approved comments for this post
		$args = array(
			'post_id' => $post->ID,
			'status'  => 'approve',
			'number'  => 999999,
		);

		$comments = get_comments( $args );
		if ( empty( $comments ) ) {
			return $content;
		}

		// Process comments in reverse order (newest first) to avoid offset issues
		$comments = array_reverse( $comments );

		foreach ( $comments as $comment ) {
			$comment_meta = get_comment_meta( $comment->comment_ID, 'cf_front_comment_meta', true );
			if ( empty( $comment_meta ) ) {
				continue;
			}

			$comment_meta_array = json_decode( $comment_meta, true );
			if ( ! is_array( $comment_meta_array ) || empty( $comment_meta_array['comment_on_text'] ) ) {
				continue;
			}

			$comment_text = $comment_meta_array['comment_on_text'];
			$datatext     = $comment_meta_array['datatext'] ?? '';
			$block_id     = $comment_meta_array['block_id'] ?? '';
			$block_name   = $comment_meta_array['block_name'] ?? '';
			$highlight_id = $comment_meta_array['highlight_id'] ?? 'icfp-highlight-' . $comment->comment_ID;

			// Skip if no datatext and no comment ID
			if ( empty( $datatext ) && empty( $comment->comment_ID ) ) {
				continue;
			}

			// Check if mark already exists in content (avoid duplicates)
			$mark_pattern = '/<mark[^>]*data-icfp-highlight-id="' . preg_quote( esc_attr( $highlight_id ), '/' ) . '"[^>]*>/i';
			if ( preg_match( $mark_pattern, $content ) ) {
				continue; // Mark already exists, skip
			}

			// Escape the comment text for regex, handling HTML entities
			$comment_text_escaped = htmlspecialchars( $comment_text, ENT_QUOTES, 'UTF-8' );
			$escaped_text = preg_quote( $comment_text_escaped, '/' );
			// Normalize whitespace for matching (handle both spaces and HTML entities)
			$escaped_text = preg_replace( '/\s+/', '[\s&nbsp;]+', $escaped_text );

			// If block_id is provided, try to find the text only within that specific block
			$search_content = $content;
			$block_content = '';
			
			if ( ! empty( $block_id ) ) {
				// Try to find the block by its data-icfp-block-id attribute
				$block_pattern = '/<[^>]+\s+data-icfp-block-id=["\']' . preg_quote( esc_attr( $block_id ), '/' ) . '["\'][^>]*>.*?<\/[^>]+>/is';
				if ( preg_match( $block_pattern, $content, $block_matches ) ) {
					$block_content = $block_matches[0];
					$search_content = $block_content;
				}
			}

			// Try to find the text in the content (either full content or specific block)
			$pattern = '/' . $escaped_text . '/iu';
			
			if ( preg_match( $pattern, $search_content, $matches, PREG_OFFSET_CAPTURE ) ) {
				$match_text = $matches[0][0];

				// Build the mark element with all attributes
				// Note: We don't add 'mdspan-front-comment' class here - it will be added
				// only when user clicks on a comment from the slider
				$mark_attrs = array(
					'datatext'               => esc_attr( $datatext ?: 'legacy_' . $comment->comment_ID ),
					'id'                     => esc_attr( $highlight_id ),
					'data-icfp-highlight-id' => esc_attr( $highlight_id ),
					'data-comment-id'        => esc_attr( $comment->comment_ID ),
				);

				if ( ! empty( $block_id ) ) {
					$mark_attrs['data-icfp-block-id'] = esc_attr( $block_id );
				}
				if ( ! empty( $block_name ) ) {
					$mark_attrs['data-icfp-block-name'] = esc_attr( $block_name );
				}

				// Build attributes string
				$attrs_string = '';
				foreach ( $mark_attrs as $attr => $value ) {
					$attrs_string .= ' ' . esc_attr( $attr ) . '="' . esc_attr( $value ) . '"';
				}

				// Wrap the matched text with mark element
				$replacement = '<mark' . $attrs_string . '>' . $match_text . '</mark>';
				
				// If we found the block, replace only within that block
				if ( ! empty( $block_content ) ) {
					$updated_block = preg_replace( $pattern, $replacement, $block_content, 1 );
					$content = str_replace( $block_content, $updated_block, $content );
				} else {
					// Replace in full content (first match only)
					$content = preg_replace( $pattern, $replacement, $content, 1 );
				}
			}
		}

		return $content;
	}

	/**
	 * Checks if a comment already exists for the selected text.
	 * Used to prevent duplicate comments on the same text selection.
	 *
	 * @return void
	 */
	public function icfp_check_duplicate_comment_function() {
		$nonce = filter_input( INPUT_POST, 'nonce', FILTER_SANITIZE_SPECIAL_CHARS );
		if ( isset( $nonce ) && ! wp_verify_nonce( sanitize_key( $nonce ), 'cf_public_nonce' ) ) {
			echo wp_json_encode(
				array(
					'is_duplicate' => false,
					'error'        => 'Invalid nonce',
				)
			);
			wp_die();
		}

		$selection = filter_input( INPUT_POST, 'selection', FILTER_SANITIZE_SPECIAL_CHARS );
		$page_id   = filter_input( INPUT_POST, 'pageID', FILTER_SANITIZE_SPECIAL_CHARS );

		if ( empty( $selection ) || empty( $page_id ) ) {
			echo wp_json_encode(
				array(
					'is_duplicate' => false,
				)
			);
			wp_die();
		}

		// Unslash the selection (WordPress adds slashes)
		$selection = wp_unslash( $selection );
		// Decode HTML entities and Unicode entity strings
		$normalized_selection = wp_strip_all_tags( html_entity_decode( $selection, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) );
		// Replace any remaining Unicode entity strings (like "u2018" or "u2019") with actual characters
		$normalized_selection = preg_replace_callback( '/u([0-9a-fA-F]{4})/', function( $matches ) {
			return mb_convert_encoding( '&#x' . $matches[1] . ';', 'UTF-8', 'HTML-ENTITIES' );
		}, $normalized_selection );
		$normalized_selection = trim( $normalized_selection );

		// Get all approved comments for this post.
		$all_comments = get_comments(
			array(
				'post_id' => $page_id,
				'status'  => 'approve',
				'number'  => 999999,
			)
		);

		$is_duplicate = false;

		// Check each comment's metadata for matching selected text.
		foreach ( $all_comments as $existing_comment ) {
			$existing_meta = get_comment_meta(
				$existing_comment->comment_ID,
				'cf_front_comment_meta',
				true
			);

			if ( ! empty( $existing_meta ) ) {
				$existing_meta_array = json_decode( $existing_meta, true );
				if (
					is_array( $existing_meta_array ) &&
					isset( $existing_meta_array['comment_on_text'] )
				) {
					$existing_text = wp_strip_all_tags(
						html_entity_decode( $existing_meta_array['comment_on_text'] )
					);
					$existing_text = trim( $existing_text );

					// Compare normalized text (case-insensitive, whitespace-normalized).
					if (
						strtolower( $normalized_selection ) ===
						strtolower( $existing_text )
					) {
						$is_duplicate = true;
						break;
					}
				}
			}
		}

		echo wp_json_encode(
			array(
				'is_duplicate' => $is_duplicate,
			)
		);

		wp_die();
	}

	/**
	* Handles the front-end comment submission functionality for the "Inline Comments for Post" plugin.
	*
	* This function is called when a user submits a comment on the front-end of the website. It verifies the nonce, retrieves the submitted data, and updates the comment metadata with the selected text.
	*
	* @return void
	*/
	public function icfp_add_front_comment_function() {

        $nonce = filter_input( INPUT_POST, 'nonce', FILTER_SANITIZE_SPECIAL_CHARS );
		if ( isset($nonce) && ! wp_verify_nonce( sanitize_key( $nonce ), 'cf_public_nonce' ) ) {
			echo 'failed';
			wp_die();
		}
		if ( ! isset( $nonce ) ) {
			echo 'failed';
			wp_die();
		}
		// Use FILTER_UNSAFE_RAW for selection to preserve special characters like curly quotes
		// We'll sanitize it properly after decoding HTML entities
		$selection     = filter_input( INPUT_POST, 'selection', FILTER_UNSAFE_RAW );
		$page_id       = filter_input( INPUT_POST, 'pageID', FILTER_SANITIZE_SPECIAL_CHARS );
		$comment_text  = filter_input( INPUT_POST, 'commentText', FILTER_SANITIZE_SPECIAL_CHARS );

		// Check if a comment already exists for this selected text.
		// This prevents duplicate comments on the same text selection.
		if ( ! empty( $selection ) ) {
			// Unslash the selection (WordPress adds slashes)
			$selection = wp_unslash( $selection );
			// Decode HTML entities and Unicode entity strings
			$normalized_selection = wp_strip_all_tags( html_entity_decode( $selection, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) );
			// Replace any remaining Unicode entity strings (like "u2018" or "u2019") with actual characters
			$normalized_selection = preg_replace_callback( '/u([0-9a-fA-F]{4})/', function( $matches ) {
				return mb_convert_encoding( '&#x' . $matches[1] . ';', 'UTF-8', 'HTML-ENTITIES' );
			}, $normalized_selection );
			$normalized_selection = trim( $normalized_selection );

			// Get all comments for this post.
			$all_comments = get_comments(
				array(
					'post_id' => $page_id,
					'status'  => 'approve',
					'number'  => 999999,
				)
			);

			// Check each comment's metadata for matching selected text.
			foreach ( $all_comments as $existing_comment ) {
				$existing_meta = get_comment_meta(
					$existing_comment->comment_ID,
					'cf_front_comment_meta',
					true
				);

				if ( ! empty( $existing_meta ) ) {
					$existing_meta_array = json_decode( $existing_meta, true );
					if (
						is_array( $existing_meta_array ) &&
						isset( $existing_meta_array['comment_on_text'] )
					) {
						$existing_text = wp_strip_all_tags(
							html_entity_decode( $existing_meta_array['comment_on_text'], ENT_QUOTES | ENT_HTML5, 'UTF-8' )
						);
						// Replace any Unicode entity strings with actual characters
						$existing_text = preg_replace_callback( '/u([0-9a-fA-F]{4})/', function( $matches ) {
							return mb_convert_encoding( '&#x' . $matches[1] . ';', 'UTF-8', 'HTML-ENTITIES' );
						}, $existing_text );
						$existing_text = trim( $existing_text );

						// Compare normalized text (case-insensitive, whitespace-normalized).
						if (
							strtolower( $normalized_selection ) ===
							strtolower( $existing_text )
						) {
							// Duplicate found - return error message.
							echo wp_json_encode(
								array(
									'success' => false,
									'message' => __(
										'A comment already exists for this selected text. Please select different text or reply to the existing comment.',
										'inline-comments-for-post'
									),
									'comments' => array(),
								)
							);
							wp_die();
						}
					}
				}
			}
		}

		$args = array(
			'number' => '1',
			'post_id' => $page_id
		);
		$comments = get_comments($args);

		if( isset( $comments ) && !empty( $comments ) ) {
			$lastcomment = $comments[0];
			$comment_id = $lastcomment->comment_ID;
			$comment_meta_array                       = array();
			
			// Ensure selection is properly retrieved and cleaned
			$clean_selection = '';
			if ( ! empty( $selection ) ) {
				// Unslash the selection (WordPress adds slashes)
				$selection = wp_unslash( $selection );
				// Decode HTML entities first, then strip tags to preserve text content
				// Use ENT_QUOTES | ENT_HTML5 to properly decode all entities including Unicode
				$clean_selection = wp_strip_all_tags( html_entity_decode( $selection, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) );
				// Replace any remaining Unicode entity strings (like "u2018" or "u2019") with actual characters
				$clean_selection = preg_replace_callback( '/u([0-9a-fA-F]{4})/', function( $matches ) {
					return mb_convert_encoding( '&#x' . $matches[1] . ';', 'UTF-8', 'HTML-ENTITIES' );
				}, $clean_selection );
				$clean_selection = trim( $clean_selection );
			}
			
			$comment_meta_array['comment_on_text']    = $clean_selection;
			// Store the stable comment highlight ID.
			$comment_meta_array['highlight_id']       = 'icfp-highlight-' . $comment_id;
			update_comment_meta( $comment_id, 'cf_front_comment_meta', wp_json_encode( $comment_meta_array ) );
		}

		$args_comment = array(
			'post_id' => $page_id,
			'number' => 999999,
		);
		$comments = get_comments($args_comment, true);

		if ( ! empty( $comments ) && is_array( $comments ) && count( $comments ) > 0 ) {
			echo wp_json_encode( array(
				'success' => true,
				'comments' => $comments,
				'comment_id' => $comment_id ?? null, // Return the comment ID
			) );
		} else {
			echo wp_json_encode( array(
				'success' => false,
				'comments' => array(),
				'comment_id' => $comment_id ?? null,
			) );
		}

		wp_die();
	}

	/**
	 * Get all comments with their metadata for restoring mark elements on page load.
	 *
	 * @return void
	 */
	public function icfp_get_comment_marks_function() {
		// Verify nonce.
		if ( ! wp_verify_nonce( $_POST['nonce'], 'cf_public_nonce' ) ) {
			echo wp_json_encode(
				array(
					'success' => false,
					'message' => 'Invalid nonce',
				)
			);
			wp_die();
		}

		// Sanitize and retrieve input
		$post_id = filter_input( INPUT_POST, 'pageID', FILTER_SANITIZE_NUMBER_INT );

		if ( ! $post_id ) {
			echo wp_json_encode(
				array(
					'success' => false,
					'message' => 'Invalid post ID',
					'marks'   => array(),
				)
			);
			wp_die();
		}

		// Get all approved and pending comments for this post
		// Include pending comments so newly submitted comments are also restored
		$args = array(
			'post_id' => $post_id,
			'status'  => 'approve', // Only approved comments for now (pending comments might not have all metadata)
			'number'  => 999999,
		);

		$comments = get_comments( $args );
		$marks    = array();

		foreach ( $comments as $comment ) {
			$comment_meta = get_comment_meta( $comment->comment_ID, 'cf_front_comment_meta', true );

			if ( ! empty( $comment_meta ) ) {
				$comment_meta_array = json_decode( $comment_meta, true );

				if (
					is_array( $comment_meta_array ) &&
					! empty( $comment_meta_array['comment_on_text'] )
				) {
					$marks[] = array(
						'comment_id'     => $comment->comment_ID,
						'text'           => $comment_meta_array['comment_on_text'],
					);
				}
			}
		}

		echo wp_json_encode(
			array(
				'success' => true,
				'marks'   => $marks,
			)
		);

		wp_die();
	}

	/**
	 * Convert comment time to a human-readable format.
	 *
	 * @param int $comment_id The ID of the comment.
	 * @return string Human-readable time difference.
	 */
	public function icfp_human_readable_comment_time( $comment_id ) {
	    // Get the comment time
	    //$comment_time = get_comment_time('U', true, $comment_id);
	    $comment_time = get_comment_time( 'U', '','', $comment_id );

	    // Get the current time
	    $current_time = current_time( 'timestamp' );

	    // Calculate the time difference in seconds
	    $time_difference = $current_time - $comment_time;

	    // Define time periods in seconds
	    $periods = array(
	        'second' => 1,
	        'minute' => 60,
	        'hour' => 3600,
	        'day' => 86400,
	        'week' => 604800,
	        'month' => 2592000,
	        'year' => 31536000
	    );

	    // Initialize the period and value
	    $period = 'second';
	    $value = $time_difference;

	    // Determine the appropriate time period
	    foreach ( $periods as $key => $seconds ) {
	        if ( $time_difference < $seconds ) {
	            break;
	        }
	        $period = $key;
	        $value = floor( $time_difference / $seconds );
	    }

	    // Handle specific cases for "1 day ago" and "yesterday"
	    if ($period == 'day' && $value == 1) {
	        return __( 'yesterday', 'inline-comments-for-post' );
	    } elseif ( $period == 'day' && $value == 2 ) {
	        return __( '2 days ago', 'inline-comments-for-post' );
	    }

	    // Generate the human-readable time difference
	    if ($value > 1) {
	        $period .= 's';
	    }

	    // translators: %1$d is the number of time units, %2$s is the unit of time (e.g., minutes, hours).
	    return sprintf(__('%1$d %2$s ago', 'inline-comments-for-post'), $value, $period);
	}

	/**
	 * Get the list of comments.
	 *
	 * @return void
	 */
	public function icfp_get_comment_function() {

		// Verify nonce.
		if ( ! wp_verify_nonce( $_POST['nonce'], 'cf_public_nonce' ) ) {
			echo wp_json_encode(
				array(
					'success' => false,
					'message' => 'Invalid nonce',
				)
			);
			wp_die();
		}

		// Sanitize and retrieve input
		$post_id = filter_input( INPUT_POST, 'pageID', FILTER_SANITIZE_NUMBER_INT );
		$sort_by = filter_input( INPUT_POST, 'sortBy', FILTER_SANITIZE_FULL_SPECIAL_CHARS );

		// Define the base arguments for the comments query
		$args = array(
			'post_id' => $post_id,
			'status'  => 'approve',  // First, retrieve approved comments
		);

		// // Sort comments by relevant or recent.
		// if ( 'relevant' === $sort_by ) {
		// 	$args['orderby'] = 'comment_karma';
		// 	$args['order']   = 'DESC';
		// } else {
		// 	$args['orderby'] = 'comment_date';
		// 	$args['order']   = 'DESC';
		// }

		// Get approved comments
		$approved_comments = get_comments( $args );

		// // Now retrieve pending comments
		// $args['status'] = 'hold'; // Change the status to 'hold' to get pending comments
		// $pending_comments = get_comments( $args );

		// // Merge the results of approved and pending comments
		// $all_comments = array_merge( $approved_comments, $pending_comments );

		// // Optionally, you can sort the merged comments again if needed (e.g., by comment date)
		// usort( $all_comments, function( $a, $b ) {
		// 	return strtotime( $b->comment_date ) - strtotime( $a->comment_date );
		// });

		ob_start();
		?>
		<ul class="cf-front-comment-list">
		<?php
			$comment_depth = $this->icfp_comment_settings['icfp_comment_depth'] ?? 5;

			wp_list_comments(array(
				'style' => 'ul', // Use 'ul' and 'li' for structure
				'callback' => array( $this, 'icfp_get_comment_callback' ), // Use custom callback
				'max_depth' => $comment_depth, // Set max depth of nested comments
			), $approved_comments);
			?>
		</ul>
		<?php
		$content = ob_get_clean();

		echo wp_json_encode( array(
			'success' => true,
			'content' => $content,
		) );

		wp_die();
	}

	/**
	 * Get the comment callback.
	 *
	 * @param object $comment Comment object.
	 * @param array  $args Comment arguments.
	 * @param int    $depth Comment depth.
	 * @return void
	 */
	public function icfp_get_comment_callback($comment, $args, $depth) {
		$comment_id = get_comment_ID();
		$comment_class = 'comment-' . $comment_id;
		$child_class = 'child-comment-' . $comment_id;
		$comment_depth = $this->icfp_comment_settings['icfp_comment_depth'] ?? 5;

		?>
		<li>
			<div class="cf-front-comment <?php echo esc_attr($comment_class); ?>" id="comment-<?php comment_ID(); ?>">
				<div class="cf-front-comment-main">
					<?php
						if ( ! empty( $this->icfp_comment_settings['icfp_show_user_avatar'] ) ) {
						?>
						<div class="comment-author cf-front-comment-section">
							<?php echo get_avatar( $comment, 32 ); ?>
						</div>
						<?php
						}
					?>
					<div class="comment-meta commentmetadata">
						<div class="cf-front-comment-date"><?php echo wp_kses_post( get_comment_author_link($comment->comment_ID) ); ?></div>
						<?php
							if ( ! empty( $this->icfp_comment_settings['icfp_show_comment_time'] ) ) {
							?>
							<div class="cf-front-comment-time">
								<a href="<?php echo wp_kses_post( get_comment_link( $comment_id ) ); ?>">
									<?php echo $this->icfp_human_readable_comment_time( $comment_id ); ?>
								</a>
							</div>
							<?php
							}
						?>
					</div>
				</div>
				<div class="cf-front-comment-text-para">
					<?php 
					$comment_meta = get_comment_meta( $comment->comment_ID, 'cf_front_comment_meta', true );

					if( isset( $comment_meta ) && !empty( $comment_meta ) ) {
						$comment_meta = json_decode( $comment_meta, true );
						if( isset( $comment_meta['comment_on_text'] ) && !empty( $comment_meta['comment_on_text'] ) ) {
							?>
							<?php
							// Properly decode the comment text, handling Unicode entities
							$display_text = $comment_meta['comment_on_text'];
							// Replace Unicode entity strings (like "u2018", "u2019") with actual characters
							$display_text = preg_replace_callback( '/u([0-9a-fA-F]{4})/', function( $matches ) {
								return mb_convert_encoding( '&#x' . $matches[1] . ';', 'UTF-8', 'HTML-ENTITIES' );
							}, $display_text );
							?>
							<div class="cf-inline-feedback-wrapper" onclick="cfFrontCommentOnClick(this)" data-comment-id="<?php echo esc_attr( $comment->comment_ID ); ?>" data-content="<?php echo esc_attr( $display_text ); ?>">
								<span class="cf-inline-feedback-info">
								<mark class="cf-front-comment-except">
									<?php
										$comment_text = esc_html( $display_text );
										if ( ! $this->is_valid_url( $comment_text ) ) {
											echo esc_html( $display_text );
										} else {
											echo esc_html( 'Click here to see the Media' );
										}
									?>
								</mark>
								</span> 
							</div>
							<?php
						}
					}
					?>
					<?php comment_text($comment->comment_ID); ?>
				</div>
				<div class="cf-front-comment-reply">
					<?php
						if ( is_user_logged_in() ) {
					?>
						<a href="<?php echo esc_url( get_edit_comment_link( $comment_id ) ); ?>" class="cf-front-comment-edit-link">Edit</a>
					<?php 
						}
					?>
					<?php
						if ( ! empty( $this->icfp_comment_settings['icfp_enable_reply_to_comment'] ) ) {
							comment_reply_link( array_merge( $args, array( 'depth' => $depth, 'max_depth' => $comment_depth ) ) );
						}
					?>
				</div>
				<?php /* if ($depth < $args['max_depth']) : ?>
					<ul class="children <?php echo esc_attr($child_class); ?>">
						<?php
						// This is where child comments will be displayed
						?>
					</ul>
				<?php endif; */ ?>
			</div>
		</li>
		<?php
	}

	/**
	 * Custom reply link.
	 *
	 * @param string $link Comment reply link.
	 * @param array  $args Comment arguments.
	 * @param object $comment Comment object.
	 * @param object $post Post object.
	 * @return string
	 */
	public function icfp_custom_reply_link($link, $args, $comment, $post) {
		$link = str_replace('onclick=', 'data-onclick=', $link);
		return $link;
	}

	/**
	 * Check if the URL is valid.
	 *
	 * @param string $url URL to check.
	 * @return bool
	 */
	private function is_valid_url( $url ) {
		return filter_var( $url, FILTER_VALIDATE_URL ) !== false;
	}
}
