<?php

/**
 * AJAX handlers for AnchorKit plugin
 *
 * @package AnchorKit
 */

/** @noinspection PhpUndefinedFunctionInspection */

/**
 * Ajax handlers for real-time settings updates
 */

// Exit if accessed directly
if (!defined('ABSPATH')) {
	exit;
}

/**
 * Recursively sanitize settings array from AJAX requests.
 *
 * @param mixed $data The data to sanitize (array, string, bool, or numeric).
 * @return mixed Sanitized data with the same structure.
 */
function anchorkit_sanitize_settings_array($data, $parent_key = '')
{
	if (!is_array($data)) {
		// Use unified sanitization if we have a key
		if ($parent_key !== '' && function_exists('anchorkit_sanitize_option_input')) {
			return anchorkit_sanitize_option_input($parent_key, $data);
		}

		if (is_bool($data)) {
			return (bool) $data;
		}
		if (is_numeric($data)) {
			return is_float($data + 0) ? (float) $data : (int) $data;
		}
		return sanitize_text_field((string) $data);
	}

	$sanitized = array();
	foreach ($data as $key => $value) {
		$safe_key = sanitize_key($key);
		// Pass the key down to allow contextual sanitization
		$sanitized[$safe_key] = anchorkit_sanitize_settings_array($value, $safe_key);
	}
	return $sanitized;
}

/**
 * Register AJAX handlers for AnchorKit (with backward compatibility)
 */
function anchorkit_register_ajax_handlers()
{
	// Canonical AnchorKit action names.
	add_action('wp_ajax_anchorkit_update_setting', 'anchorkit_ajax_update_setting');
	add_action('wp_ajax_anchorkit_reset_settings', 'anchorkit_ajax_reset_settings');
	add_action('wp_ajax_anchorkit_save_custom_icon', 'anchorkit_ajax_save_custom_icon');

	// TOC Preview HTML generation - single source of truth
	add_action('wp_ajax_anchorkit_generate_toc_preview', 'anchorkit_ajax_generate_toc_preview');
}
add_action('init', 'anchorkit_register_ajax_handlers');

/**
 * AJAX handler to update a setting
 */
function anchorkit_ajax_update_setting()
{
	// Check nonce for security - support both the original and new nonce names
	$nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
	if (!wp_verify_nonce($nonce, 'anchorkit_ajax_nonce')) {
		wp_send_json_error(array('message' => 'Security check failed'));
		exit;
	}

	// Check if user has permission
	if (!current_user_can('manage_options')) {
		wp_send_json_error(array('message' => 'Permission denied'));
		exit;
	}

	// Get and sanitize parameters
	$option_name = isset($_POST['option_name']) ? sanitize_text_field(wp_unslash($_POST['option_name'])) : '';
	// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Value is sanitized contextually below based on option type
	$option_value = isset($_POST['option_value']) ? wp_unslash($_POST['option_value']) : '';

	if ($option_name === '') {
		wp_send_json_error(array('message' => 'Missing option name'));
		exit;
	}

	// Handle array-notation option names like "anchorkit_toc_schema_type_per_post_type[post]"
	// These need to be merged into the existing array option.
	$array_key = null;
	$base_option_name = $option_name;
	if (preg_match('/^([a-zA-Z0-9_]+)\[([^\]]+)\]$/', $option_name, $matches)) {
		$base_option_name = $matches[1];
		$array_key = $matches[2];
	}

	if ($array_key !== null) {
		// Get existing array value, then set/update the specific key
		$existing_array = get_option($base_option_name, array());
		if (!is_array($existing_array)) {
			$existing_array = array();
		}

		// Sanitize the value for this key
		$sanitized_value = sanitize_text_field($option_value);

		// If value is empty, remove the key (use global default), otherwise set it
		if ($sanitized_value === '') {
			unset($existing_array[$array_key]);
		} else {
			$existing_array[$array_key] = $sanitized_value;
		}

		$option_value = $existing_array;
		$option_name = $base_option_name;
	} else {
		// Single-source sanitization for all settings
		if (function_exists('anchorkit_sanitize_option_input')) {
			$option_value = anchorkit_sanitize_option_input($option_name, $option_value);
		} else {
			$option_value = sanitize_text_field($option_value);
		}
	}

	// Get the existing option value
	$existing_value = get_option($option_name, false);

	// Check if the value is actually changing
	$is_same_value = ($existing_value == $option_value); // loose comparison to handle type differences

	// Always use update_option - it creates the option if it doesn't exist
	// This is more reliable than add_option which can return false for various reasons
	$result = update_option($option_name, $option_value);

	// If update_option returns false but value matches what we're trying to set,
	// verify by reading it back and consider it success if it matches
	if (!$result) {
		$verify_value = get_option($option_name);
		if ($verify_value === $option_value) {
			$result = true; // Value is correct in database, consider it success
		}
	}

	// Consider it a success if the update succeeded OR if the value didn't change
	if ($result || $is_same_value) {
		wp_send_json_success(
			array(
				'message' => 'Setting updated successfully',
				'option_name' => $option_name,
				'option_value' => $option_value,
				'status' => 'updated',
				'unchanged' => $is_same_value,
			)
		);
	} else {
		wp_send_json_error(
			array(
				'message' => 'Failed to update setting',
				'option_name' => $option_name,
				'status' => 'error',
				'sanitized_value' => $option_value,
				'original_value' => $option_value,
			)
		);
	}

	exit;
}

/**
 * AJAX handler to reset settings to default values
 */
function anchorkit_ajax_reset_settings()
{
	// Check nonce for security - support both the original and new nonce names
	$nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
	if (!wp_verify_nonce($nonce, 'anchorkit_ajax_nonce')) {
		wp_send_json_error(array('message' => 'Security check failed'));
		exit;
	}

	// Check if user has permission
	if (!current_user_can('manage_options')) {
		wp_send_json_error(array('message' => 'Permission denied'));
		exit;
	}

	// Get settings to reset (validate and sanitize all array values recursively)
	$settings = array();
	if (isset($_POST['settings']) && is_array($_POST['settings'])) {
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Value is sanitized recursively by anchorkit_sanitize_settings_array()
		$settings = anchorkit_sanitize_settings_array(wp_unslash($_POST['settings']));
	}

	if (empty($settings) || !is_array($settings)) {
		wp_send_json_error(array('message' => 'No settings provided'));
		exit;
	}

	// Define default values for all settings.
	$defaults = array(
		// Reading Time - General Settings
		'anchorkit_wpm' => 300,
		'anchorkit_insert_before_content' => true,
		'anchorkit_insert_before_excerpt' => false,
		'anchorkit_enable_shortcode' => true,

		// Reading Time - Page Text
		'anchorkit_label' => 'Reading Time:',
		'anchorkit_postfix' => 'minutes',
		'anchorkit_postfix_singular' => 'minute',

		// Reading Time - Excerpt Text
		'anchorkit_excerpt_label' => 'Reading Time:',
		'anchorkit_excerpt_postfix' => 'minutes',
		'anchorkit_excerpt_postfix_singular' => 'minute',

		// Reading Time - Page Typography
		'anchorkit_text_size_value' => '1.25',
		'anchorkit_text_size_unit' => 'rem',
		'anchorkit_prefix_font_weight' => 'bold',
		'anchorkit_prefix_color' => '#4F4F4F',
		'anchorkit_text_font_weight' => 'normal',
		'anchorkit_text_color' => '#717171',

		// Reading Time - Excerpt Typography
		'anchorkit_excerpt_text_size_value' => '1',
		'anchorkit_excerpt_text_size_unit' => 'rem',
		'anchorkit_excerpt_prefix_font_weight' => 'bold',
		'anchorkit_excerpt_prefix_color' => '#4F4F4F',
		'anchorkit_excerpt_text_font_weight' => 'normal',
		'anchorkit_excerpt_text_color' => '#717171',

		// Progress Bar Settings
		'anchorkit_progress_bar_position' => 'top',
		'anchorkit_progress_bar_thickness_value' => '4',
		'anchorkit_progress_bar_thickness_unit' => 'px',
		'anchorkit_progress_bar_color' => '#2c7be5',
		'anchorkit_progress_bar_aria_label' => 'Reading Progress Bar',
		'anchorkit_progress_bar_custom_css' => '',
		'anchorkit_progress_bar_async_load' => true,
		'anchorkit_progress_bar_animation_type' => 'linear',
		'anchorkit_progress_bar_animation_speed' => 300,
		'anchorkit_progress_bar_preview_enabled' => true,
		'anchorkit_progress_bar_trigger_mode' => 'full_page',
		'anchorkit_progress_bar_target_selector' => '',

		// Back to Top Settings
		'anchorkit_back_to_top_width' => '40',
		'anchorkit_back_to_top_height' => '40',
		'anchorkit_back_to_top_opacity' => '80',
		'anchorkit_back_to_top_autohide' => true,
		'anchorkit_back_to_top_fade_duration' => '300',
		'anchorkit_back_to_top_position' => 'bottom-right',
		'anchorkit_back_to_top_margin_x' => '20',
		'anchorkit_back_to_top_margin_y' => '20',
		'anchorkit_back_to_top_icon_type' => 'collection',
		'anchorkit_back_to_top_icon_color' => '#ffffff',
		'anchorkit_back_to_top_bg_color' => '#000000',
		'anchorkit_back_to_top_hover_color' => '#444444',
		'anchorkit_back_to_top_scroll_offset' => '100',
		'anchorkit_back_to_top_scroll_duration' => '400',
		'anchorkit_back_to_top_scroll_animation' => 'ease-out',
		'anchorkit_back_to_top_hide_small_device' => false,
		'anchorkit_back_to_top_small_device_width' => '640',
		'anchorkit_back_to_top_hide_small_window' => false,
		'anchorkit_back_to_top_small_window_width' => '640',
		'anchorkit_back_to_top_auto_hide_after' => '0',
		'anchorkit_back_to_top_collection_icon' => 'arrow-up-bold.svg',
		'anchorkit_back_to_top_icon_width' => '16',
		'anchorkit_back_to_top_icon_height' => '16',
		'anchorkit_back_to_top_homepage_only' => false,
		'anchorkit_back_to_top_async' => true,
		'anchorkit_back_to_top_show_test_button' => true,
		'anchorkit_back_to_top_progress_indicator' => false,
		'anchorkit_back_to_top_progress_color' => '#ff5555',
		'anchorkit_back_to_top_progress_thickness' => '3',

		// Table of Contents Settings
		'anchorkit_toc_enabled' => true,
		'anchorkit_toc_post_types' => array('post', 'page'),
		'anchorkit_toc_automatic_insertion' => true,
		'anchorkit_toc_position' => 'before_first_heading',
		'anchorkit_toc_collapsible' => true,
		'anchorkit_toc_initial_state' => 'expanded',
		'anchorkit_toc_smooth_scroll' => true,
		'anchorkit_toc_hierarchical_view' => true,
		'anchorkit_toc_show_numerals' => false,
		'anchorkit_toc_bullet_style' => 'disc',
		'anchorkit_toc_bullet_character' => '•',
		'anchorkit_toc_numbering_style' => 'hierarchical',
		'anchorkit_toc_numbering_format' => 'decimal',
		'anchorkit_toc_numbering_separator' => '.',
		'anchorkit_toc_live_preview_enabled' => true,
		'anchorkit_toc_theme' => 'system',
		// Light mode color defaults
		'anchorkit_toc_bg_color_light' => '#FFFFFF',
		'anchorkit_toc_text_color_light' => '#333333',
		'anchorkit_toc_link_color_light' => '#0073AA',
		'anchorkit_toc_link_hover_color_light' => '#005177',
		'anchorkit_toc_active_link_color_light' => '#00A0D2',
		'anchorkit_toc_border_color_light' => '#DDDDDD',
		'anchorkit_toc_bullet_color_light' => '#0073AA',
		// Dark mode color defaults
		'anchorkit_toc_bg_color_dark' => '#1e1e1e',
		'anchorkit_toc_text_color_dark' => '#e0e0e0',
		'anchorkit_toc_link_color_dark' => '#7ec4ee',
		'anchorkit_toc_link_hover_color_dark' => '#a8d8f0',
		'anchorkit_toc_active_link_color_dark' => '#5ba3d0',
		'anchorkit_toc_border_color_dark' => '#404040',
		'anchorkit_toc_bullet_color_dark' => '#7ec4ee',
		// Legacy color defaults (keep for backward compatibility)
		'anchorkit_toc_bg_color' => '#FFFFFF',
		'anchorkit_toc_text_color' => '#333333',
		'anchorkit_toc_link_color' => '#0073AA',
		'anchorkit_toc_link_hover_color' => '#005177',
		'anchorkit_toc_active_link_color' => '#00A0D2',
		'anchorkit_toc_border_color' => '#DDDDDD',
		'anchorkit_toc_font_family' => 'inherit',
		'anchorkit_toc_font_size' => 14,
		'anchorkit_toc_padding' => 15,
		'anchorkit_toc_border_width' => 1,
		'anchorkit_toc_border_radius' => 4,
		'anchorkit_toc_include_headings' => array('h2', 'h3', 'h4'),
		'anchorkit_toc_min_headings' => 2,
		'anchorkit_toc_exclude_selectors' => '',
		'anchorkit_toc_title_text' => 'Table of Contents',
		'anchorkit_toc_show_label' => true,
		'anchorkit_toc_style_preset' => 'minimal',
		'anchorkit_toc_scroll_offset' => 0,
		'anchorkit_toc_width' => 80,
		'anchorkit_toc_max_width' => 600,
		'anchorkit_toc_min_width' => 280,
		'anchorkit_toc_alignment' => 'center',
		'anchorkit_toc_float' => 'none',
		'anchorkit_toc_custom_styling' => false,
		'anchorkit_toc_hide_on_mobile' => false,
		'anchorkit_toc_mobile_breakpoint' => 782,
		'anchorkit_toc_aria_label' => '',
		'anchorkit_toc_back_to_top_link' => false,
		'anchorkit_toc_back_to_top_text' => 'Back to Top',
		'anchorkit_toc_back_to_top_font_size' => 14,
		'anchorkit_toc_custom_labels' => '',
		'anchorkit_toc_anchor_format' => 'auto',
		'anchorkit_toc_anchor_prefix' => 'section',
		// Pro features - Sticky TOC
		'anchorkit_toc_sticky_enabled' => false,
		'anchorkit_toc_sticky_position' => 'content',
		'anchorkit_toc_sticky_offset' => 20,
		// Pro features - Advanced Styling
		'anchorkit_toc_box_shadow_enabled' => false,
		'anchorkit_toc_box_shadow_custom' => '0 4px 6px rgba(0, 0, 0, 0.1)',
		'anchorkit_toc_box_shadow_light' => '0 4px 6px rgba(0, 0, 0, 0.1)',
		'anchorkit_toc_box_shadow_dark' => '0 2px 8px rgba(0, 0, 0, 0.3)',
		// Box Shadow Components - Light Mode
		'anchorkit_toc_shadow_h_offset_light' => 0,
		'anchorkit_toc_shadow_v_offset_light' => 4,
		'anchorkit_toc_shadow_blur_light' => 6,
		'anchorkit_toc_shadow_spread_light' => 0,
		'anchorkit_toc_shadow_color_light' => '#000000',
		'anchorkit_toc_shadow_opacity_light' => 0.1,
		// Box Shadow Components - Dark Mode
		'anchorkit_toc_shadow_h_offset_dark' => 0,
		'anchorkit_toc_shadow_v_offset_dark' => 2,
		'anchorkit_toc_shadow_blur_dark' => 8,
		'anchorkit_toc_shadow_spread_dark' => 0,
		'anchorkit_toc_shadow_color_dark' => '#000000',
		'anchorkit_toc_shadow_opacity_dark' => 0.3,
		'anchorkit_toc_entrance_animation' => false,
		'anchorkit_toc_animation_type' => 'fade',
		'anchorkit_toc_line_height' => 1.6,
		'anchorkit_toc_letter_spacing' => 0,
		'anchorkit_toc_text_transform' => 'none',
		'anchorkit_toc_custom_id' => '',
		'anchorkit_toc_custom_class' => '',
		// Pro features - Advanced Typography
		'anchorkit_toc_advanced_typography_override' => false,
		'anchorkit_toc_title_font_size' => '20',
		'anchorkit_toc_h2_font_size' => '18',
		'anchorkit_toc_h3_font_size' => '16',
		'anchorkit_toc_h4_font_size' => '14',
		'anchorkit_toc_h5_font_size' => '13',
		'anchorkit_toc_h6_font_size' => '12',
		// Pro features - Advanced Content Filtering
		'anchorkit_toc_exclude_keywords' => '',
		'anchorkit_toc_exclude_regex' => '',
		// Pro features - Smart Heading Detection
		'anchorkit_toc_auto_fix_hierarchy' => false,
		'anchorkit_toc_min_heading_depth' => 2,
		'anchorkit_toc_max_heading_depth' => 4,
		// Pro features - Reading Time & Metadata
		'anchorkit_toc_show_reading_time' => false,
		'anchorkit_toc_reading_speed' => 200,
		'anchorkit_toc_show_word_count' => false,
		'anchorkit_toc_time_format' => 'min_read',
		// Pro features - Schema.org & Rich Snippets
		'anchorkit_toc_schema_enabled' => false,
		'anchorkit_toc_schema_type' => 'Article',
		// Pro features - Enhanced Navigation
		'anchorkit_toc_scroll_easing' => 'ease-in-out',
		'anchorkit_toc_scroll_duration' => 500,
		// Pro features - View More
		'anchorkit_toc_view_more_enabled' => false,
		'anchorkit_toc_initial_count' => 5,
		'anchorkit_toc_view_more_text' => 'View More',
		'anchorkit_toc_view_less_text' => 'View Less',
		// Pro features - ACF Integration
		'anchorkit_toc_acf_enabled' => false,
		'anchorkit_toc_acf_field_names' => '',
		'anchorkit_toc_acf_merge_mode' => 'after',
		// Pro features - AMP Compatibility
		'anchorkit_toc_amp_enabled' => false,
	);

	$results = array();
	$success_count = 0;
	$unchanged_count = 0;

	// Reset each setting to its default value if it differs from the default
	foreach ($settings as $setting) {
		$setting = sanitize_text_field($setting);

		// Skip if no default exists
		if (!isset($defaults[$setting])) {
			$results[$setting] = array(
				'status' => 'error',
				'message' => 'No default value',
			);
			continue;
		}

		// Get current value
		$current_value = get_option($setting);
		$default_value = $defaults[$setting];

		// Check if current value equals default
		$is_equal = false;

		// Special handling for arrays
		if (is_array($current_value) && is_array($default_value)) {
			$current_json = wp_json_encode($current_value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
			$default_json = wp_json_encode($default_value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

			if (false !== $current_json && false !== $default_json) {
				$is_equal = ($current_json === $default_json);
			} else {
				// Fallback if encoding fails for any reason.
				$is_equal = ($current_value === $default_value);
			}
		} else {
			// For color values, do case-insensitive comparison
			if (
				is_string($current_value) && is_string($default_value) &&
				(strpos($current_value, '#') === 0 || strpos($default_value, '#') === 0)
			) {
				$is_equal = (strtolower($current_value) === strtolower($default_value));
			} elseif (is_bool($default_value) || $default_value === false || $default_value === true) {
				// Convert to boolean for comparison
				$is_equal = ((bool) $current_value === (bool) $default_value);
			} else {
				$is_equal = ($current_value === $default_value);
			}
		}

		// If already at default, skip updating
		if ($is_equal) {
			$results[$setting] = array(
				'status' => 'unchanged',
				'message' => 'Already at default value',
			);
			++$unchanged_count;
			continue;
		}

		// Update to default value
		$result = update_option($setting, $default_value);

		if ($result) {
			$results[$setting] = array(
				'status' => 'success',
				'message' => 'Reset to default',
			);
			++$success_count;
		} else {
			$results[$setting] = array(
				'status' => 'error',
				'message' => 'Failed to update',
			);
		}
	}

	if ($success_count > 0) {
		wp_send_json_success(
			array(
				'message' => 'Settings reset successfully',
				'results' => $results,
				'success_count' => $success_count,
				'unchanged_count' => $unchanged_count,
			)
		);
	} elseif ($unchanged_count > 0) {
		wp_send_json_success(
			array(
				'message' => 'All settings already at default values',
				'results' => $results,
				'success_count' => 0,
				'unchanged_count' => $unchanged_count,
			)
		);
	} else {
		wp_send_json_error(
			array(
				'message' => 'Failed to reset settings',
				'results' => $results,
				'success_count' => $success_count,
				'unchanged_count' => $unchanged_count,
				'debug' => array(
					'settings_requested' => $settings,
					'settings_with_defaults' => array_keys($defaults),
				),
			)
		);
	}

	exit;
}

/**
 * AJAX handler to save custom icon URL
 */
function anchorkit_ajax_save_custom_icon()
{
	// Check nonce for security - support both the original and new nonce names
	$nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
	if (!wp_verify_nonce($nonce, 'anchorkit_ajax_nonce')) {
		wp_send_json_error(array('message' => 'Security check failed'));
		exit;
	}

	// Check if user has permission
	if (!current_user_can('manage_options')) {
		wp_send_json_error(array('message' => 'Permission denied'));
		exit;
	}

	// Get and sanitize the icon URL
	$option_name = 'anchorkit_back_to_top_custom_icon';
	// Use esc_url_raw first to satisfy plugin checker, then apply our custom sanitization
	$raw_url = isset($_POST['icon_url']) ? esc_url_raw(wp_unslash($_POST['icon_url'])) : '';
	$icon_url = anchorkit_sanitize_option_input($option_name, $raw_url);


	if ($icon_url === '') {
		// If clearing the icon (empty URL), just return success
		delete_option($option_name);
		wp_send_json_success(
			array(
				'message' => 'Custom icon removed successfully',
				'icon_url' => '',
			)
		);
		exit;
	}

	// Check if the option already exists
	$existing_value = get_option($option_name, false);

	if ($existing_value === false) {
		// Option doesn't exist, add it
		$result = add_option($option_name, $icon_url);
	} else {
		// Option exists, update it
		$result = update_option($option_name, $icon_url);
	}

	// Double-check the saved value
	$saved_value = get_option($option_name);

	if ($result && $saved_value === $icon_url) {
		wp_send_json_success(
			array(
				'message' => 'Custom icon saved successfully',
				'icon_url' => $icon_url,
			)
		);
	} else {
		// Try to diagnose the issue
		$error_message = '';
		if (!$result) {
			$error_message = 'Database update failed';
		} elseif ($saved_value !== $icon_url) {
			$error_message = 'Value mismatch after save';
		} else {
			$error_message = 'Unknown error occurred';
		}

		wp_send_json_error(
			array(
				'message' => $error_message,
				'debug' => array(
					'attempted_url' => $icon_url,
					'saved_url' => $saved_value,
					'update_result' => $result,
					'option_existed' => $existing_value !== false,
				),
			)
		);
	}

	exit;
}

/**
 * Add a notification system for real-time feedback
 */
function anchorkit_add_notification_container()
{
	$screen = get_current_screen();
	if ($screen->id !== 'settings_page_anchorkit-settings') {
		return;
	}

	// SVG icons for notifications (hardcoded, safe values)
	// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- SVG icons are hardcoded safe strings
	$check_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 20px; height: 20px; fill: #81c995;"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>';
	$error_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 20px; height: 20px; fill: #f9dedc;"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>';
	$info_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 20px; height: 20px; fill: #b9deff;"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>';

	echo '<div id="anchorkit-notification" class="anchorkit-notification" style="position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%) translateY(20px); min-width: 320px; max-width: 420px; z-index: 100000; opacity: 0; visibility: hidden; transition: opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1), visibility 0.15s cubic-bezier(0.4, 0, 0.2, 1), transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);">
        <div class="anchorkit-notification-content" style="background-color: #333333; color: #ffffff; border-radius: 8px; padding: 12px 16px; box-shadow: 0 2px 4px rgba(0,0,0,0.2); display: flex; align-items: center; justify-content: space-between; box-sizing: border-box; max-width: 100%;">
            <div class="anchorkit-notification-icon success-icon" style="display: none; margin-right: 12px; width: 20px; height: 20px; flex-shrink: 0; align-items: center; justify-content: center;">' . $check_icon . '</div>
            <div class="anchorkit-notification-icon error-icon" style="display: none; margin-right: 12px; width: 20px; height: 20px; flex-shrink: 0; align-items: center; justify-content: center;">' . $error_icon . '</div>
            <div class="anchorkit-notification-icon info-icon" style="display: none; margin-right: 12px; width: 20px; height: 20px; flex-shrink: 0; align-items: center; justify-content: center;">' . $info_icon . '</div>
            <span class="anchorkit-notification-message" style="font-size: 14px; font-weight: 500; line-height: 20px; letter-spacing: 0.1px; flex-grow: 1; margin-right: 8px;"></span>
            <button class="anchorkit-notification-close" aria-label="Close notification" style="background: none; border: none; padding: 4px; margin: -4px; color: rgba(255, 255, 255, 0.7); width: 20px; height: 20px; font-size: 18px; line-height: 20px; cursor: pointer; display: flex; align-items: center; justify-content: center; border-radius: 50%; flex-shrink: 0; transition: background-color 0.2s ease;">&times;</button>
        </div>
    </div>';
	// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
}
add_action('admin_footer', 'anchorkit_add_notification_container');

/**
 * AJAX handler to generate TOC preview HTML using the same function as frontend
 * This ensures preview and frontend use identical HTML structure
 */
function anchorkit_ajax_generate_toc_preview()
{
	// Check nonce for security
	$nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
	if (!wp_verify_nonce($nonce, 'anchorkit_ajax_nonce')) {
		wp_send_json_error(array('message' => 'Security check failed'));
		exit;
	}

	// Check if user has permission
	if (!current_user_can('manage_options')) {
		wp_send_json_error(array('message' => 'Permission denied'));
		exit;
	}

	// Build option overrides from the request (do NOT persist to DB)
	// Validate and sanitize all array values recursively
	$settings_to_save = array();
	if (isset($_POST['settings']) && is_array($_POST['settings'])) {
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Value is sanitized recursively by anchorkit_sanitize_settings_array()
		$settings_to_save = anchorkit_sanitize_settings_array(wp_unslash($_POST['settings']));
	}
	$overrides = array();
	if (!empty($settings_to_save) && is_array($settings_to_save)) {
		foreach ($settings_to_save as $key => $value) {
			if (is_string($key) && strpos($key, 'anchorkit_toc_') === 0) {
				$overrides[$key] = $value;
			}
		}
	}

	$applied_overrides = array();
	if (function_exists('anchorkit_apply_option_overrides')) {
		$applied_overrides = anchorkit_apply_option_overrides($overrides);
	}

	// Get heading levels from settings (support both legacy and canonical option names).
	$heading_levels = array('h2', 'h3', 'h4'); // Default
	if (!empty($overrides['anchorkit_toc_include_headings']) && is_array($overrides['anchorkit_toc_include_headings'])) {
		$heading_levels = $overrides['anchorkit_toc_include_headings'];
	} else {
		$heading_levels = anchorkit_get_option('anchorkit_toc_include_headings', array('h2', 'h3', 'h4'));
		if (!is_array($heading_levels)) {
			$heading_levels = array('h2', 'h3', 'h4');
		}
	}

	// Generate sample headings for preview (matching structure from initTocPreview)
	// Include word_count for reading time and word count metadata display
	// Include all heading levels, then filter based on selected levels
	$all_sample_headings = array(
		array(
			'text' => 'Introduction',
			'anchor' => 'toc-main-heading',
			'level' => 2,
			'word_count' => 180, // ~1 min read at 200 WPM
		),
		array(
			'text' => 'Getting Started',
			'anchor' => 'toc-second-heading',
			'level' => 2,
			'word_count' => 320, // ~2 min read at 200 WPM
		),
		array(
			'text' => 'Installation',
			'anchor' => 'toc-sub-heading',
			'level' => 3,
			'word_count' => 150, // ~1 min read at 200 WPM
		),
		array(
			'text' => 'Configuration',
			'anchor' => 'toc-sub-heading2',
			'level' => 3,
			'word_count' => 280, // ~1 min read at 200 WPM
		),
		array(
			'text' => 'Basic Settings',
			'anchor' => 'toc-sub-sub-heading',
			'level' => 4,
			'word_count' => 120, // <1 min read at 200 WPM
		),
		array(
			'text' => 'Advanced Options',
			'anchor' => 'toc-sub-sub-heading2',
			'level' => 4,
			'word_count' => 450, // ~2 min read at 200 WPM
		),
		array(
			'text' => 'Additional Details',
			'anchor' => 'toc-h5-heading',
			'level' => 5,
			'word_count' => 100, // <1 min read at 200 WPM
		),
		array(
			'text' => 'Fine Print',
			'anchor' => 'toc-h6-heading',
			'level' => 6,
			'word_count' => 80, // <1 min read at 200 WPM
		),
		array(
			'text' => 'Features',
			'anchor' => 'toc-third-heading',
			'level' => 2,
			'word_count' => 600, // ~3 min read at 200 WPM
		),
		array(
			'text' => 'Conclusion',
			'anchor' => 'toc-conclusion',
			'level' => 2,
			'word_count' => 200, // ~1 min read at 200 WPM
		),
	);

	// Filter sample headings based on selected heading levels
	$sample_headings = array_filter(
		$all_sample_headings,
		function ($heading) use ($heading_levels) {
			$level_str = 'h' . $heading['level'];
			return in_array($level_str, $heading_levels, true);
		}
	);

	// Re-index array after filtering
	$sample_headings = array_values($sample_headings);

	// If no headings match, use default H2, H3, H4
	if (empty($sample_headings)) {
		$sample_headings = array_filter(
			$all_sample_headings,
			function ($heading) {
				return in_array($heading['level'], array(2, 3, 4), true);
			}
		);
		$sample_headings = array_values($sample_headings);
	}

	// Generate TOC HTML using the same function as frontend
	if (!function_exists('anchorkit_toc_generate_html')) {
		wp_send_json_error(array('message' => 'TOC generation function not found'));
		exit;
	}

	try {
		$toc_context = array(
			'source' => 'admin_preview',
			'data' => array(
				'preview' => true,
				'requested_levels' => $heading_levels,
			),
		);
		$toc_html = anchorkit_toc_generate_html($sample_headings, '', $toc_context);

		$tokens = function_exists('anchorkit_collect_toc_tokens') ? anchorkit_collect_toc_tokens() : array(
			'light' => array(),
			'dark' => array(),
		);

		// Default to free version (no pro features)
		$theme = anchorkit_get_option('anchorkit_toc_theme', 'system');

		$hierarchical_option = anchorkit_get_option('anchorkit_toc_hierarchical_view', 'not_set');
		$hierarchical_view = ($hierarchical_option === 'not_set') ? true : (bool) $hierarchical_option;

		$alignment = anchorkit_get_option('anchorkit_toc_alignment', 'center');
		$alignment = in_array($alignment, array('left', 'center', 'right'), true) ? $alignment : 'center';

		$state = array(
			'theme' => $theme,
			'style_preset' => anchorkit_get_option('anchorkit_toc_style_preset', 'minimal'),
			'custom_styling' => (bool) anchorkit_get_option('anchorkit_toc_custom_styling', false),
			'title' => anchorkit_get_option('anchorkit_toc_title_text', 'Table of Contents'),
			'show_label' => (bool) anchorkit_get_option('anchorkit_toc_show_label', true),
			'collapsible' => (bool) anchorkit_get_option('anchorkit_toc_collapsible', true),
			'initial_state' => anchorkit_get_option('anchorkit_toc_initial_state', 'expanded'),
			'hierarchical' => $hierarchical_view,
			'show_numerals' => (bool) anchorkit_get_option('anchorkit_toc_show_numerals', false),
			'numbering_style' => anchorkit_get_option('anchorkit_toc_numbering_style', 'hierarchical'),
			'width' => (int) anchorkit_get_option('anchorkit_toc_width', 80),
			'float' => anchorkit_get_option('anchorkit_toc_float', 'none'),
			'alignment' => $alignment,
			'view_more' => array(
				'enabled' => (bool) anchorkit_get_option('anchorkit_toc_view_more_enabled', false),
				'initial_count' => (int) anchorkit_get_option('anchorkit_toc_initial_count', 5),
				'more_text' => anchorkit_get_option('anchorkit_toc_view_more_text', 'View More'),
				'less_text' => anchorkit_get_option('anchorkit_toc_view_less_text', 'View Less'),
			),
			'back_to_top' => array(
				'enabled' => (bool) anchorkit_get_option('anchorkit_toc_back_to_top_link', false),
				'text' => anchorkit_get_option('anchorkit_toc_back_to_top_text', 'Back to Top'),
				'font_size' => (int) anchorkit_get_option('anchorkit_toc_back_to_top_font_size', 14),
			),
			'sticky' => array(
				'enabled' => false,
				'position' => 'content',
				'offset' => 20,
			),
			'animation' => array(
				'enabled' => false,
				'type' => 'none',
			),
			'mobile' => array(
				'hide_on_mobile' => (bool) anchorkit_get_option('anchorkit_toc_hide_on_mobile', false),
				'breakpoint' => (int) anchorkit_get_option('anchorkit_toc_mobile_breakpoint', 782),
			),
		);

		// Premium feature overrides - this entire block is stripped from free version
		if (anchorkit_fs() && anchorkit_fs()->is__premium_only()) {
			if (anchorkit_fs()->can_use_premium_code()) {
				$state['sticky'] = array(
					'enabled' => (bool) anchorkit_get_option('anchorkit_toc_sticky_enabled', false),
					'position' => anchorkit_get_option('anchorkit_toc_sticky_position', 'content'),
					'offset' => (int) anchorkit_get_option('anchorkit_toc_sticky_offset', 20),
				);
				$state['animation'] = array(
					'enabled' => (bool) anchorkit_get_option('anchorkit_toc_entrance_animation', false),
					'type' => anchorkit_get_option('anchorkit_toc_animation_type', 'fade'),
				);
			}
		}

		wp_send_json_success(
			array(
				'html' => $toc_html,
				'tokens' => $tokens,
				'state' => $state,
				'message' => 'TOC preview generated successfully',
			)
		);
	} finally {
		if (!empty($applied_overrides) && function_exists('anchorkit_remove_option_overrides')) {
			anchorkit_remove_option_overrides($applied_overrides);
		}
	}

	exit;
}
