<?php

/**
 * Helper functions for AnchorKit
 *
 * @package AnchorKit
 */

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

/**
 * Returns an array of allowed HTML tags for wp_kses() when outputting TOC.
 *
 * @since 1.0.0
 * @return array The allowed tags and attributes.
 */
if (!function_exists('anchorkit_get_allowed_html_tags')) {
	function anchorkit_get_allowed_html_tags()
	{
		return array(
			'nav' => array(
				'class' => array(),
				'id' => array(),
				'role' => array(),
				'aria-label' => array(),
				'style' => array(),
				'data-anchorkit-auto-theme' => array(),
				'data-mobile-breakpoint' => array(),
				'data-sticky' => array(),
				'data-sticky-position' => array(),
				'data-sticky-offset' => array(),
				'data-anchorkit-instance' => array(),
				'aria-expanded' => array(),
				'data-style' => array(),
			),
			'div' => array(
				'class' => array(),
				'id' => array(),
				'role' => array(),
				'style' => array(),
				'data-initial-count' => array(),
				'data-view-more-text' => array(),
				'data-view-less-text' => array(),
				'aria-expanded' => array(),
			),
			'hr' => array(
				'class' => array(),
				'style' => array(),
			),
			'svg' => array(
				'class' => array(),
				'xmlns' => array(),
				'width' => array(),
				'height' => array(),
				'viewbox' => array(),
				'fill' => array(),
				'stroke' => array(),
				'stroke-width' => array(),
				'stroke-linecap' => array(),
				'stroke-linejoin' => array(),
				'aria-hidden' => array(),
				'focusable' => array(),
			),
			'path' => array(
				'd' => array(),
				'fill' => array(),
				'stroke' => array(),
				'stroke-width' => array(),
				'stroke-linecap' => array(),
				'stroke-linejoin' => array(),
			),
			'polyline' => array(
				'points' => array(),
				'fill' => array(),
				'stroke' => array(),
				'stroke-width' => array(),
				'stroke-linecap' => array(),
				'stroke-linejoin' => array(),
			),
			'line' => array(
				'x1' => array(),
				'y1' => array(),
				'x2' => array(),
				'y2' => array(),
				'stroke' => array(),
				'stroke-width' => array(),
			),
			'ul' => array(
				'class' => array(),
				'id' => array(),
				'style' => array(),
			),
			'li' => array(
				'class' => array(),
				'id' => array(),
				'data-level' => array(),
				'style' => array(),
			),
			'a' => array(
				'href' => array(),
				'class' => array(),
				'role' => array(),
				'aria-label' => array(),
				'target' => array(),
				'rel' => array(),
				'style' => array(),
			),
			'span' => array(
				'class' => array(),
				'style' => array(),
			),
			'button' => array(
				'class' => array(),
				'id' => array(),
				'type' => array(),
				'data-initial-count' => array(),
				'data-view-more-text' => array(),
				'data-view-less-text' => array(),
				'aria-expanded' => array(),
				'aria-controls' => array(),
				'aria-label' => array(),
				'style' => array(),
			),
			'i' => array(
				'class' => array(),
				'aria-hidden' => array(),
			),
			'code' => array(),
			'br' => array(),
			'b' => array(),
			'strong' => array(),
			'em' => array(),
			'h1' => array(
				'class' => array(),
				'id' => array(),
			),
			'h2' => array(
				'class' => array(),
				'id' => array(),
			),
			'h3' => array(
				'class' => array(),
				'id' => array(),
			),
			'h4' => array(
				'class' => array(),
				'id' => array(),
			),
			'h5' => array(
				'class' => array(),
				'id' => array(),
			),
			'h6' => array(
				'class' => array(),
				'id' => array(),
			),
		);
	}
}

/**
 * Centralized Debug Logging
 *
 * Provides a consistent way to log debug messages throughout the plugin.
 * Debug mode is controlled by WordPress's WP_DEBUG constant.
 *
 * @since 1.0.0
 * @param string $message The message to log
 * @param string $context Optional context (e.g., 'Elementor', 'Gutenberg', 'Auto-Insert')
 * @return void
 */
if (!function_exists('anchorkit_debug_log')) {
	function anchorkit_debug_log($message, $context = '')
	{
		// Only log if WP_DEBUG is enabled
		if (!defined('WP_DEBUG') || !WP_DEBUG) {
			return;
		}

		// Only log if error_log function exists (it should always exist)
		if (!function_exists('error_log')) {
			return;
		}

		$prefix = 'AnchorKit';
		if (!empty($context)) {
			$prefix .= ' [' . $context . ']';
		}

		// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging only in WP_DEBUG mode
		error_log($prefix . ': ' . $message);
	}
}

/**
 * Generates a standardized color picker input field
 *
 * @param string $name          The name attribute for the input
 * @param string $value         The current color value
 * @param string $label         The label text
 * @param string $description   Optional description text
 * @param array  $args          Optional additional arguments
 *
 * @return string The HTML for the color picker
 */
function anchorkit_color_picker($name, $value, $label, $description = '', $args = array())
{
	$defaults = array(
		'id' => $name,
		'class' => '',
		'data_attributes' => array(),
		'field_class' => '',
		'container_class' => '',
	);

	$args = wp_parse_args($args, $defaults);

	// Process data attributes
	$data_attr_html = '';
	foreach ($args['data_attributes'] as $data_key => $data_value) {
		$data_attr_html .= sprintf(' data-%s="%s"', esc_attr($data_key), esc_attr($data_value));
	}

	// Start output buffer to capture the HTML
	ob_start();
	?>
	<div class="form-group <?php echo esc_attr($args['container_class']); ?>">
		<div class="anchorkit-color-picker <?php echo esc_attr($args['field_class']); ?>">
			<label for="<?php echo esc_attr($args['id']); ?>"><?php echo esc_html($label); ?></label>
			<input type="color" name="<?php echo esc_attr($name); ?>" id="<?php echo esc_attr($args['id']); ?>"
				value="<?php echo esc_attr($value); ?>" class="<?php echo esc_attr($args['class']); ?>" <?php
					  // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Data attributes are escaped with esc_attr() when built
				  	echo $data_attr_html;
					  ?>>
			<span class="color-value"><?php echo esc_html(strtoupper($value)); ?></span>
			<?php if (!empty($description)): ?>
				<span class="helper-text"><?php echo wp_kses_post($description); ?></span>
			<?php endif; ?>
		</div>
	</div>
	<?php
	return ob_get_clean();
}

/**
 * Generates a tooltip icon with content
 *
 * @param string $content       The tooltip content (supports HTML)
 * @param string $position      Position of tooltip: 'top' (default) or 'right'
 * @param array  $args          Optional additional arguments
 *
 * @return string The HTML for the tooltip
 */
function anchorkit_tooltip($content, $position = 'top', $args = array())
{
	$defaults = array(
		'icon' => 'i',
		'wrapper_class' => '',
	);

	$args = wp_parse_args($args, $defaults);

	$position_class = ($position === 'right') ? 'tooltip-right' : '';
	$wrapper_class = trim('anchorkit-tooltip-wrapper ' . $position_class . ' ' . $args['wrapper_class']);

	ob_start();
	?>
	<span class="<?php echo esc_attr($wrapper_class); ?>">
		<span class="anchorkit-tooltip-icon" tabindex="0" role="button"
			aria-label="More information"><?php echo esc_html($args['icon']); ?></span>
		<span class="anchorkit-tooltip-content" role="tooltip">
			<?php echo wp_kses_post($content); ?>
		</span>
	</span>
	<?php
	return ob_get_clean();
}

/**
 * Check if user has pro features enabled
 *
 * During development: returns true for testing
 * After launch: will check Freemius license status
 *
 * You can also define ANCHORKIT_DEV_PRO_MODE in wp-config.php:
 * define('ANCHORKIT_DEV_PRO_MODE', true); // Enable all pro features for testing
 * define('ANCHORKIT_DEV_PRO_MODE', false); // Test as free user
 *
 * @return bool True if user has access to pro features, false otherwise
 */
if (!function_exists('anchorkit_debug_log')) {
	/**
	 * Minimal debug logger that only fires when WP_DEBUG is enabled.
	 *
	 * @param mixed  $message Message or data to log.
	 * @param string $context Optional prefix to help identify the source.
	 * @return void
	 */
	function anchorkit_debug_log($message, $context = 'AnchorKit')
	{
		if (!defined('WP_DEBUG') || WP_DEBUG !== true) {
			return;
		}

		if (is_array($message) || is_object($message)) {
			// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- Debug logging only in WP_DEBUG mode
			$message = print_r($message, true);
		}

		if (!empty($context)) {
			$message = '[' . $context . '] ' . $message;
		}

		// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging only in WP_DEBUG mode
		error_log($message);
	}
}

if (!function_exists('anchorkit_get_checkout_url')) {
	/**
	 * Generate a Freemius checkout link for the current site.
	 *
	 * Uses Freemius's built-in checkout_url() method which automatically:
	 * - Detects sandbox vs production mode
	 * - Handles sandbox authentication tokens
	 * - Respects environment settings
	 *
	 * @param int|null $pricing_id
	 * @param array    $extra
	 * @return string
	 */
	function anchorkit_get_checkout_url($pricing_id = null, $extra = array())
	{
		$default_url = 'https://getanchorkit.com/pricing/';

		$fs = anchorkit_fs();

		// If Freemius SDK not available, use fallback URL
		if (!$fs) {
			if ($pricing_id) {
				return add_query_arg('pricing_id', $pricing_id, $default_url);
			}
			return $default_url;
		}

		// Build params array for Freemius checkout
		$params = is_array($extra) ? $extra : array();

		// Add pricing_id if provided
		if ($pricing_id) {
			$params['pricing_id'] = $pricing_id;
		}

		// Use annual billing by default
		$billing_cycle = defined('WP_FS__PERIOD_ANNUALLY') ? WP_FS__PERIOD_ANNUALLY : 'annual';

		// Use Freemius's built-in checkout_url() method
		// This automatically handles sandbox/production mode detection
		return $fs->checkout_url($billing_cycle, false, $params);
	}
}

if (!function_exists('anchorkit_get_pro_plan_cards')) {
	/**
	 * Returns the plan data used for the Pro tab cards.
	 *
	 * @return array[]
	 */
	function anchorkit_get_pro_plan_cards()
	{
		$plans = array(
			array(
				'id' => 'single',
				'label' => __('Single Site', 'anchorkit-table-of-contents'),
				'sites' => __('1 Site', 'anchorkit-table-of-contents'),
				'price' => '$59/yr',
				'description' => __('Perfect for blogs and solopreneurs.', 'anchorkit-table-of-contents'),
				'pricing_id' => defined('ANCHORKIT_FREEMIUS_PRICE_SINGLE') ? ANCHORKIT_FREEMIUS_PRICE_SINGLE : null,
			),
			array(
				'id' => 'agency',
				'label' => __('Professional', 'anchorkit-table-of-contents'),
				'sites' => __('10 Sites', 'anchorkit-table-of-contents'),
				'price' => '$79/yr',
				'description' => __('For growing teams managing multiple client properties.', 'anchorkit-table-of-contents'),
				'pricing_id' => defined('ANCHORKIT_FREEMIUS_PRICE_TEN_SITE') ? ANCHORKIT_FREEMIUS_PRICE_TEN_SITE : null,
			),
			array(
				'id' => 'unlimited',
				'label' => __('Unlimited', 'anchorkit-table-of-contents'),
				'sites' => __('Unlimited Sites', 'anchorkit-table-of-contents'),
				'price' => '$199/yr',
				'description' => __('Best for agencies and SaaS platforms with high-volume deployments.', 'anchorkit-table-of-contents'),
				'pricing_id' => defined('ANCHORKIT_FREEMIUS_PRICE_UNLIMITED') ? ANCHORKIT_FREEMIUS_PRICE_UNLIMITED : null,
			),
		);

		foreach ($plans as &$plan) {
			$plan['checkout_url'] = anchorkit_get_checkout_url($plan['pricing_id']);
		}

		return $plans;
	}
}

if (!function_exists('anchorkit_prepare_toc_context')) {
	/**
	 * Build a standardized context array for TOC rendering hooks.
	 *
	 * @param array $overrides Context values supplied by the caller.
	 * @return array
	 */
	function anchorkit_prepare_toc_context($overrides = array())
	{
		global $post;

		$defaults = array(
			'source' => 'auto_insertion',
			'post_id' => ($post && isset($post->ID)) ? (int) $post->ID : 0,
			'is_admin' => is_admin(),
			'is_rest' => defined('REST_REQUEST') && REST_REQUEST,
			'data' => array(),
			'render_settings' => array(),
		);

		$overrides = is_array($overrides) ? $overrides : array();

		if (!isset($overrides['data']) || !is_array($overrides['data'])) {
			$overrides['data'] = array();
		}

		if (!isset($overrides['render_settings']) || !is_array($overrides['render_settings'])) {
			$overrides['render_settings'] = array();
		}

		$context = wp_parse_args($overrides, $defaults);

		/**
		 * Filters the full TOC context before it is used elsewhere.
		 *
		 * @param array $context
		 */
		return apply_filters('anchorkit_toc_context', $context);
	}
}

/**
 * Return list of option names that should be treated as booleans.
 *
 * @return array
 */
function anchorkit_get_boolean_option_names()
{
	static $boolean_options = null;

	if ($boolean_options === null) {
		$boolean_options = array(
			'anchorkit_enable_feature',
			'anchorkit_enable_shortcode',
			'anchorkit_insert_before_content',
			'anchorkit_insert_before_excerpt',
			'anchorkit_progress_bar_preview_enabled',
			'anchorkit_progress_bar_async_load',
			'anchorkit_back_to_top_enabled',
			'anchorkit_back_to_top_autohide',
			'anchorkit_back_to_top_hide_small_device',
			'anchorkit_back_to_top_hide_small_window',
			'anchorkit_back_to_top_homepage_only',
			'anchorkit_back_to_top_async',
			'anchorkit_back_to_top_show_test_button',
			'anchorkit_back_to_top_progress_indicator',
			// Table of Contents boolean options
			'anchorkit_toc_enabled',
			'anchorkit_toc_automatic_insertion',
			'anchorkit_toc_collapsible',
			'anchorkit_toc_smooth_scroll',
			'anchorkit_toc_hierarchical_view',
			'anchorkit_toc_show_numerals',
			'anchorkit_toc_live_preview_enabled',
			'anchorkit_toc_hide_on_mobile',
			'anchorkit_toc_back_to_top_link',
			'anchorkit_toc_view_more_enabled',
			'anchorkit_toc_custom_styling',
			'anchorkit_toc_show_label',
			'anchorkit_toc_box_shadow_enabled',
			'anchorkit_toc_sticky_enabled',
			'anchorkit_toc_entrance_animation',
			'anchorkit_toc_show_reading_time',
			'anchorkit_toc_show_word_count',
			'anchorkit_toc_auto_fix_hierarchy',
			'anchorkit_toc_schema_enabled',
			'anchorkit_toc_scroll_spy',
			'anchorkit_toc_acf_enabled',
			'anchorkit_toc_amp_enabled',
		);
	}

	return $boolean_options;
}

/**
 * Return numeric limits configuration for TOC settings.
 *
 * @return array
 */
function anchorkit_get_numeric_option_limits()
{
	static $numeric_limits = null;

	if ($numeric_limits === null) {
		$numeric_limits = array(
			'anchorkit_wpm' => array(50, 1000, 'int'),
			'anchorkit_text_size_value' => array(0.5, 5, 'float'),
			'anchorkit_excerpt_text_size_value' => array(0.5, 5, 'float'),
			'anchorkit_progress_bar_thickness_value' => array(1, 20, 'float'),
			'anchorkit_progress_bar_animation_speed' => array(50, 2000, 'int'),
			'anchorkit_back_to_top_width' => array(16, 200, 'int'),
			'anchorkit_back_to_top_height' => array(16, 200, 'int'),
			'anchorkit_back_to_top_opacity' => array(10, 100, 'int'),
			'anchorkit_back_to_top_fade_duration' => array(100, 2000, 'int'),
			'anchorkit_back_to_top_margin_x' => array(0, 200, 'int'),
			'anchorkit_back_to_top_margin_y' => array(0, 200, 'int'),
			'anchorkit_back_to_top_scroll_offset' => array(0, 200, 'int'),
			'anchorkit_back_to_top_scroll_duration' => array(100, 2000, 'int'),
			'anchorkit_back_to_top_small_device_width' => array(0, 2000, 'int'),
			'anchorkit_back_to_top_small_window_width' => array(0, 2000, 'int'),
			'anchorkit_back_to_top_icon_width' => array(8, 64, 'int'),
			'anchorkit_back_to_top_icon_height' => array(8, 64, 'int'),
			'anchorkit_back_to_top_auto_hide_after' => array(0, 3600, 'int'),
			'anchorkit_back_to_top_progress_thickness' => array(1, 10, 'int'),
			// Table of Contents numeric limits
			'anchorkit_toc_font_size' => array(10, 24, 'int'),
			'anchorkit_toc_padding' => array(0, 50, 'int'),
			'anchorkit_toc_border_width' => array(0, 10, 'int'),
			'anchorkit_toc_border_radius' => array(0, 30, 'int'),
			'anchorkit_toc_scroll_offset' => array(0, 200, 'int'),
			'anchorkit_toc_width' => array(20, 100, 'int'),
			'anchorkit_toc_min_headings' => array(1, 10, 'int'),
			'anchorkit_toc_mobile_breakpoint' => array(320, 1200, 'int'),
			'anchorkit_toc_sticky_offset' => array(0, 200, 'int'),
			'anchorkit_toc_shadow_h_offset_light' => array(-100, 100, 'int'),
			'anchorkit_toc_shadow_v_offset_light' => array(-100, 100, 'int'),
			'anchorkit_toc_shadow_blur_light' => array(0, 100, 'int'),
			'anchorkit_toc_shadow_spread_light' => array(-50, 50, 'int'),
			'anchorkit_toc_shadow_opacity_light' => array(0, 1, 'float'),
			'anchorkit_toc_shadow_h_offset_dark' => array(-100, 100, 'int'),
			'anchorkit_toc_shadow_v_offset_dark' => array(-100, 100, 'int'),
			'anchorkit_toc_shadow_blur_dark' => array(0, 100, 'int'),
			'anchorkit_toc_shadow_spread_dark' => array(-50, 50, 'int'),
			'anchorkit_toc_shadow_opacity_dark' => array(0, 1, 'float'),
			'anchorkit_toc_line_height' => array(1, 3, 'float'),
			'anchorkit_toc_letter_spacing' => array(-2, 5, 'float'),
			'anchorkit_toc_min_heading_depth' => array(1, 6, 'int'),
			'anchorkit_toc_max_heading_depth' => array(1, 6, 'int'),
			'anchorkit_toc_reading_speed' => array(100, 400, 'int'),
			'anchorkit_toc_scroll_duration' => array(200, 2000, 'int'),
			'anchorkit_toc_initial_count' => array(1, 50, 'int'),
			'anchorkit_toc_back_to_top_font_size' => array(10, 24, 'int'),
		);
	}

	return $numeric_limits;
}

if (!function_exists('anchorkit_normalize_heading_exclude_regex')) {
	/**
	 * Normalize the user-facing "exclude regex" field into an actual regex string.
	 *
	 * - Backwards compatible: if the value already looks like /pattern/flags it is returned verbatim.
	 * - New UX: comma/newline/pipe separated words are converted into a case-insensitive OR pattern.
	 *
	 * @param string $raw_input Raw option or attribute value supplied by the user.
	 * @return string Normalized regex pattern or empty string if nothing valid.
	 */
	function anchorkit_normalize_heading_exclude_regex($raw_input)
	{
		if (!is_string($raw_input)) {
			return '';
		}

		$raw = trim($raw_input);
		if ($raw === '') {
			return '';
		}

		// Back-compat: allow traditional /pattern/flags syntax for power users
		if ($raw[0] === '/' && substr_count($raw, '/') >= 2) {
			return $raw;
		}

		// Split on commas, pipes, or newlines to allow simple word lists
		$parts = preg_split('/[\r\n,|]+/', $raw);
		$parts = array_filter(array_map('trim', (array) $parts));
		if (empty($parts)) {
			return '';
		}

		$escaped = array_map(
			function ($term) {
				return preg_quote($term, '/');
			},
			$parts
		);

		return '/(' . implode('|', $escaped) . ')/i';
	}
}

/**
 * Sanitize and normalize a TOC option value consistently across admin and preview.
 *
 * @param string $option_name
 * @param mixed  $option_value
 * @return mixed Normalized value
 */
function anchorkit_sanitize_option_input($option_name, $option_value)
{
	if (in_array($option_name, anchorkit_get_boolean_option_names(), true)) {
		return filter_var($option_value, FILTER_VALIDATE_BOOLEAN);
	}

	if (is_array($option_value)) {
		return array_map('sanitize_text_field', $option_value);
	}

	if ($option_name === 'anchorkit_toc_custom_labels') {
		return sanitize_textarea_field(wp_unslash($option_value));
	}

	if ($option_name === 'anchorkit_toc_custom_css') {
		// Step 1: Strip all HTML/script tags
		$css = wp_strip_all_tags(wp_unslash($option_value));

		// Step 2: Remove potentially dangerous CSS patterns
		// These could be vectors for XSS or data exfiltration
		$dangerous_patterns = array(
			'/javascript\s*:/i',           // javascript: protocol
			'/expression\s*\(/i',          // IE expression()
			'/behavior\s*:/i',             // IE behavior
			'/@import\s+url\s*\(/i',       // @import with URL (can load external files)
			'/binding\s*:/i',              // XBL binding (Firefox)
			'/-moz-binding\s*:/i',         // Mozilla binding
		);

		foreach ($dangerous_patterns as $pattern) {
			$css = preg_replace($pattern, '/* removed */', $css);
		}

		return $css;
	}

	if (strpos($option_name, 'icon_url') !== false || $option_name === 'anchorkit_back_to_top_custom_icon') {
		return esc_url_raw(wp_unslash($option_value));
	}

	if (strpos($option_name, 'color') !== false) {
		$sanitized_color = sanitize_hex_color($option_value);
		if ($sanitized_color === null && is_string($option_value) && preg_match('/^[0-9a-fA-F]{6}$/', $option_value)) {
			$sanitized_color = '#' . strtolower($option_value);
		}
		return $sanitized_color ?: '';
	}

	$sanitized_value = sanitize_text_field($option_value);

	if ($option_name === 'anchorkit_toc_alignment') {
		$allowed = array('left', 'center', 'right');
		return in_array($sanitized_value, $allowed, true) ? $sanitized_value : 'center';
	}

	if ($option_name === 'anchorkit_toc_float') {
		$allowed = array('none', 'left', 'right');
		return in_array($sanitized_value, $allowed, true) ? $sanitized_value : 'none';
	}

	$numeric_limits = anchorkit_get_numeric_option_limits();
	if (isset($numeric_limits[$option_name])) {
		[$min, $max, $type] = $numeric_limits[$option_name];
		if ($type === 'int') {
			$sanitized_value = (int) $sanitized_value;
		} elseif ($type === 'float') {
			$sanitized_value = (float) $sanitized_value;
		}

		if ($sanitized_value < $min) {
			$sanitized_value = ($type === 'int') ? (int) $min : (float) $min;
		}

		if ($sanitized_value > $max) {
			$sanitized_value = ($type === 'int') ? (int) $max : (float) $max;
		}
	}

	return $sanitized_value;
}

/**
 * Apply temporary option overrides (used for previews) without touching the database.
 *
 * @param array $overrides Key/value pairs of option => value
 * @return array Array of callbacks for later removal
 */
function anchorkit_apply_option_overrides(array $overrides)
{
	$callbacks = array();

	foreach ($overrides as $option => $value) {
		$option_key = sanitize_key($option);

		if ($option_key === '' || strpos($option_key, 'anchorkit_toc_') !== 0) {
			continue;
		}

		$normalized_value = anchorkit_sanitize_option_input($option_key, $value);

		if (is_bool($normalized_value)) {
			$normalized_value = $normalized_value ? '1' : '0';
		}

		$callbacks[$option_key] = static function () use ($normalized_value) {
			return $normalized_value;
		};

		add_filter('pre_option_' . $option_key, $callbacks[$option_key]);
	}

	return $callbacks;
}

/**
 * Remove previously applied temporary option overrides.
 *
 * @param array $callbacks Array returned from anchorkit_apply_option_overrides()
 * @return void
 */
function anchorkit_remove_option_overrides(array $callbacks)
{
	foreach ($callbacks as $option => $callback) {
		remove_filter('pre_option_' . $option, $callback);
	}
}

if (!function_exists('anchorkit_get_default_for_option')) {
	/**
	 * Get the default value for a specific option
	 *
	 * @param string $option_name The option name
	 * @return mixed The default value or null if not found
	 */
	function anchorkit_get_default_for_option($option_name)
	{
		static $defaults_map = null;

		$option_name = is_string($option_name) ? sanitize_key($option_name) : '';

		if ($defaults_map === null) {
			// Build a map of option names to their default values
			$defaults_map = array(
				// Core TOC settings
				'anchorkit_toc_enabled' => true,
				'anchorkit_toc_automatic_insertion' => true,
				'anchorkit_toc_position' => 'before_first_heading',
				'anchorkit_toc_post_types' => array('post', 'page'),
				'anchorkit_toc_min_headings' => 2,
				'anchorkit_toc_include_headings' => array('h2', 'h3', 'h4'),
				'anchorkit_toc_show_label' => true,
				'anchorkit_toc_title_text' => 'Table of Contents',
				'anchorkit_toc_style_preset' => 'minimal',
				'anchorkit_toc_theme' => 'system',
				'anchorkit_toc_hierarchical_view' => true,
				'anchorkit_toc_collapsible' => true,
				'anchorkit_toc_initial_state' => 'expanded',
				'anchorkit_toc_smooth_scroll' => true,
				'anchorkit_toc_scroll_offset' => 0,
				'anchorkit_toc_scroll_duration' => 500,
				'anchorkit_toc_bullet_style' => 'disc',
				'anchorkit_toc_bullet_character' => '•',
				'anchorkit_toc_show_numerals' => false,
				'anchorkit_toc_numbering_style' => 'hierarchical',
				'anchorkit_toc_numbering_format' => 'decimal',
				'anchorkit_toc_numbering_separator' => '.',
				'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_width' => 80,
				'anchorkit_toc_max_width' => 600,
				'anchorkit_toc_min_width' => 280,
				'anchorkit_toc_alignment' => 'center',
				'anchorkit_toc_float' => 'none',
				'anchorkit_toc_hide_on_mobile' => false,
				'anchorkit_toc_mobile_breakpoint' => 782,
				'anchorkit_toc_anchor_format' => 'auto',
				'anchorkit_toc_anchor_prefix' => 'section',
				'anchorkit_toc_live_preview_enabled' => true,
				'anchorkit_toc_custom_styling' => false,
				'anchorkit_toc_min_heading_depth' => 2,
				'anchorkit_toc_max_heading_depth' => 4,
				// Colors
				'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_border_color_light' => '#DDDDDD',
				'anchorkit_toc_bullet_color_light' => '#0073AA',
				'anchorkit_toc_active_link_color_light' => '#00A0D2',
				'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_border_color_dark' => '#404040',
				'anchorkit_toc_bullet_color_dark' => '#7ec4ee',
				'anchorkit_toc_active_link_color_dark' => '#5ba3d0',
				// Pro features (defaults for free version)
				'anchorkit_toc_sticky_enabled' => false,
				'anchorkit_toc_sticky_position' => 'content',
				'anchorkit_toc_sticky_offset' => 20,
				'anchorkit_toc_scroll_spy' => false,
				'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_view_more_enabled' => false,
				'anchorkit_toc_initial_count' => 5,
				'anchorkit_toc_view_more_text' => 'View More',
				'anchorkit_toc_view_less_text' => 'View Less',
				'anchorkit_toc_show_reading_time' => false,
				'anchorkit_toc_show_word_count' => false,
				'anchorkit_toc_reading_speed' => 200,
				'anchorkit_toc_time_format' => 'min_read',
				'anchorkit_toc_acf_enabled' => false,
				'anchorkit_toc_schema_enabled' => false,
				'anchorkit_toc_schema_type' => 'Article',
				'anchorkit_toc_amp_enabled' => false,
			);
		}

		return $defaults_map[$option_name] ?? null;
	}
}

if (!function_exists('anchorkit_get_toc_default_settings')) {
	/**
	 * Retrieve sanitized global defaults for the Table of Contents feature.
	 *
	 * This mirrors the logic used by the Gutenberg block, auto-inserted TOC, and Elementor widget
	 * so every implementation starts from the exact same baseline.
	 *
	 * @return array
	 */
	function anchorkit_get_toc_default_settings()
	{
		static $cached_defaults = null;

		if ($cached_defaults !== null) {
			return $cached_defaults;
		}



		$normalize_option = static function ($option_name, $default) {
			$value = anchorkit_get_option($option_name, $default);
			if (function_exists('anchorkit_sanitize_option_input')) {
				return anchorkit_sanitize_option_input($option_name, $value);
			}

			return $value;
		};

		$get_bool_option = static function ($option_name, $default = false) use ($normalize_option) {
			$value = $normalize_option($option_name, $default ? true : false);

			if (is_bool($value)) {
				return $value;
			}

			$filtered = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
			if ($filtered !== null) {
				return $filtered;
			}

			return (bool) $value;
		};

		$get_int_option = static function ($option_name, $default = 0) use ($normalize_option) {
			$value = $normalize_option($option_name, $default);
			return is_numeric($value) ? (int) $value : (int) $default;
		};

		$get_float_option = static function ($option_name, $default = 0.0) use ($normalize_option) {
			$value = $normalize_option($option_name, $default);
			return is_numeric($value) ? (float) $value : (float) $default;
		};

		$get_string_option = static function ($option_name, $default = '') use ($normalize_option) {
			$value = $normalize_option($option_name, $default);
			if (is_string($value)) {
				return $value;
			}
			if (is_numeric($value)) {
				return (string) $value;
			}
			return (string) $default;
		};

		$get_array_option = static function ($option_name, $default = array ()) {
			$value = anchorkit_get_option($option_name, $default);
			if (!is_array($value)) {
				return $default;
			}

			$sanitized = array_map('sanitize_text_field', $value);
			$filtered = array_values(
				array_filter(
					$sanitized,
					static function ($item) {
						return $item !== '';
					}
				)
			);

			return !empty($filtered) ? $filtered : $default;
		};

		$get_color_option = static function ($option_name, $default) {
			$value = anchorkit_get_option($option_name, $default);

			if (!is_string($value)) {
				$value = $default;
			}

			$value = trim($value);
			if ($value === '') {
				$value = $default;
			}

			$sanitized = sanitize_hex_color($value);
			if ($sanitized) {
				return $sanitized;
			}

			if (preg_match('/^[0-9a-fA-F]{6}$/', $value)) {
				$candidate = '#' . strtolower($value);
				$sanitized_candidate = sanitize_hex_color($candidate);
				if ($sanitized_candidate) {
					return $sanitized_candidate;
				}
			}

			return $default;
		};

		$sanitize_choice = static function ($value, array $allowed, $fallback) {
			if (!is_string($value)) {
				return $fallback;
			}
			return in_array($value, $allowed, true) ? $value : $fallback;
		};

		$heading_levels_default = $get_array_option('anchorkit_toc_include_headings', array('h2', 'h3', 'h4'));
		$valid_heading_levels = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
		$heading_levels_default = array_values(array_intersect($valid_heading_levels, $heading_levels_default));
		if (empty($heading_levels_default)) {
			$heading_levels_default = array('h2', 'h3', 'h4');
		}

		$anchor_format = sanitize_key(anchorkit_get_option('anchorkit_toc_anchor_format', 'auto'));
		$anchor_format = $sanitize_choice($anchor_format, array('auto', 'sequential', 'prefixed'), 'auto');

		$anchor_prefix = anchorkit_get_option('anchorkit_toc_anchor_prefix', 'section');
		if (!is_string($anchor_prefix) || $anchor_prefix === '') {
			$anchor_prefix = 'section';
		}

		$aria_label = anchorkit_get_option('anchorkit_toc_aria_label', '');
		$aria_label = is_string($aria_label) ? trim($aria_label) : '';

		// Free version defaults for pro features
		$custom_labels = '';
		$acf_field_names = '';
		$acf_merge_mode = 'after';

		$valid_schema_types = array('Article', 'BlogPosting', 'WebPage', 'HowTo', 'FAQPage', 'NewsArticle', 'TechArticle', 'Course');
		$schema_type = anchorkit_get_option('anchorkit_toc_schema_type', 'Article');
		$schema_type = $sanitize_choice($schema_type, $valid_schema_types, 'Article');

		$style_preset = $sanitize_choice(
			anchorkit_get_option('anchorkit_toc_style_preset', 'minimal'),
			array('minimal', 'classic', 'modern'),
			'minimal'
		);

		$theme_preference = $sanitize_choice(
			anchorkit_get_option('anchorkit_toc_theme', 'system'),
			array('system', 'light', 'dark', 'custom'),
			'system'
		);

		$custom_styling_enabled = $get_bool_option('anchorkit_toc_custom_styling', false);

		$defaults = array(
			// Content
			'title' => $get_string_option('anchorkit_toc_title_text', 'Table of Contents'),
			'showTitle' => $get_bool_option('anchorkit_toc_show_label', true),
			'headingLevels' => $heading_levels_default,
			'excludeSelectors' => $get_string_option('anchorkit_toc_exclude_selectors', ''),
			'excludeKeywords' => $get_string_option('anchorkit_toc_exclude_keywords', ''),
			'excludeRegex' => $get_string_option('anchorkit_toc_exclude_regex', ''),
			'minHeadingsToShow' => max(1, $get_int_option('anchorkit_toc_min_headings', 2)),
			'minHeadingDepth' => max(1, $get_int_option('anchorkit_toc_min_heading_depth', 2)),
			'maxHeadingDepth' => max(1, $get_int_option('anchorkit_toc_max_heading_depth', 4)),
			// Behavior
			'hierarchicalView' => $get_bool_option('anchorkit_toc_hierarchical_view', true),
			'collapsible' => $get_bool_option('anchorkit_toc_collapsible', true),
			'initialState' => $sanitize_choice($get_string_option('anchorkit_toc_initial_state', 'expanded'), array('expanded', 'collapsed'), 'expanded'),
			'smoothScroll' => $get_bool_option('anchorkit_toc_smooth_scroll', true),
			'scrollOffset' => max(0, $get_int_option('anchorkit_toc_scroll_offset', 0)),
			'scrollEasing' => $get_string_option('anchorkit_toc_scroll_easing', 'ease-in-out'),
			'scrollDuration' => max(0, $get_int_option('anchorkit_toc_scroll_duration', 500)),
			'hideOnMobile' => $get_bool_option('anchorkit_toc_hide_on_mobile', false),
			'mobileBreakpoint' => max(320, $get_int_option('anchorkit_toc_mobile_breakpoint', 782)),
			'tocWidth' => max(20, min(100, $get_int_option('anchorkit_toc_width', 80))),
			'tocAlignment' => $sanitize_choice($get_string_option('anchorkit_toc_alignment', 'center'), array('left', 'center', 'right'), 'center'),
			'tocFloat' => $sanitize_choice($get_string_option('anchorkit_toc_float', 'none'), array('none', 'left', 'right'), 'none'),
			'sticky' => false,
			'stickyPosition' => 'content',
			'stickyOffset' => 20,
			'scrollSpy' => false,
			'backToTopLink' => false,
			'backToTopText' => $get_string_option('anchorkit_toc_back_to_top_text', 'Back to Top'),
			'backToTopFontSize' => max(10, $get_int_option('anchorkit_toc_back_to_top_font_size', 14)),
			'viewMoreEnabled' => $get_bool_option('anchorkit_toc_view_more_enabled', false),
			'viewMoreInitialCount' => max(1, $get_int_option('anchorkit_toc_initial_count', 5)),
			'viewMoreText' => $get_string_option('anchorkit_toc_view_more_text', 'View More'),
			'viewLessText' => $get_string_option('anchorkit_toc_view_less_text', 'View Less'),
			'entranceAnimation' => $get_bool_option('anchorkit_toc_entrance_animation', false),
			'animationType' => $get_string_option('anchorkit_toc_animation_type', 'fade'),
			// Appearance
			'stylePreset' => $style_preset,
			'theme' => $theme_preference,
			'bulletStyle' => $get_string_option('anchorkit_toc_bullet_style', 'disc'),
			'bulletCharacter' => $get_string_option('anchorkit_toc_bullet_character', '•'),
			'showNumerals' => $get_bool_option('anchorkit_toc_show_numerals', false),
			'numberingStyle' => $get_string_option('anchorkit_toc_numbering_style', 'hierarchical'),
			'numberingFormat' => $get_string_option('anchorkit_toc_numbering_format', 'decimal'),
			'numberingSeparator' => $get_string_option('anchorkit_toc_numbering_separator', '.'),
			'lineHeight' => $get_float_option('anchorkit_toc_line_height', 1.6),
			'letterSpacing' => $get_float_option('anchorkit_toc_letter_spacing', 0),
			'textTransform' => $sanitize_choice(
				$get_string_option('anchorkit_toc_text_transform', 'none'),
				array('none', 'uppercase', 'lowercase', 'capitalize'),
				'none'
			),
			'linkUnderline' => $sanitize_choice(
				$get_string_option('anchorkit_toc_link_underline', 'none'),
				array('none', 'always', 'hover'),
				'none'
			),
			'advancedTypographyOverride' => false,
			'titleFontSize' => $get_int_option('anchorkit_toc_title_font_size', 20),
			'h2FontSize' => $get_int_option('anchorkit_toc_h2_font_size', 18),
			'h3FontSize' => $get_int_option('anchorkit_toc_h3_font_size', 16),
			'h4FontSize' => $get_int_option('anchorkit_toc_h4_font_size', 14),
			'h5FontSize' => $get_int_option('anchorkit_toc_h5_font_size', 13),
			'h6FontSize' => $get_int_option('anchorkit_toc_h6_font_size', 12),
			'fontFamily' => $get_string_option('anchorkit_toc_font_family', 'inherit'),
			'baseFontSize' => $get_int_option('anchorkit_toc_font_size', 14),
			'padding' => max(0, $get_int_option('anchorkit_toc_padding', 15)),
			'borderWidth' => max(0, $get_int_option('anchorkit_toc_border_width', 1)),
			'borderRadius' => max(0, $get_int_option('anchorkit_toc_border_radius', 4)),
			// Advanced / SEO
			'anchorFormat' => $anchor_format,
			'anchorPrefix' => $anchor_prefix,
			'customCssClass' => $get_string_option('anchorkit_toc_custom_class', ''),
			'customLabels' => $custom_labels,
			'ariaLabel' => $aria_label,
			'customStylingEnabled' => $custom_styling_enabled,
			'showReadingTime' => false,
			'showWordCount' => false,
			'readingSpeed' => $get_int_option('anchorkit_toc_reading_speed', 200),
			'timeFormat' => $get_string_option('anchorkit_toc_time_format', 'min_read'),
			'acfEnabled' => false,
			'acfFieldNames' => $acf_field_names,
			'acfMergeMode' => $acf_merge_mode,
			'ampEnabled' => false,
			'schemaEnabled' => false,
			'schemaType' => $schema_type,
			// Colors (theme aware)
			'bgColorLight' => $get_color_option('anchorkit_toc_bg_color_light', '#FFFFFF'),
			'textColorLight' => $get_color_option('anchorkit_toc_text_color_light', '#333333'),
			'linkColorLight' => $get_color_option('anchorkit_toc_link_color_light', '#0073AA'),
			'linkHoverColorLight' => $get_color_option('anchorkit_toc_link_hover_color_light', '#005177'),
			'borderColorLight' => $get_color_option('anchorkit_toc_border_color_light', '#DDDDDD'),
			'bulletColorLight' => $get_color_option('anchorkit_toc_bullet_color_light', '#0073AA'),
			'bgColorDark' => $get_color_option('anchorkit_toc_bg_color_dark', '#1e1e1e'),
			'textColorDark' => $get_color_option('anchorkit_toc_text_color_dark', '#e0e0e0'),
			'linkColorDark' => $get_color_option('anchorkit_toc_link_color_dark', '#7ec4ee'),
			'linkHoverColorDark' => $get_color_option('anchorkit_toc_link_hover_color_dark', '#a8d8f0'),
			'borderColorDark' => $get_color_option('anchorkit_toc_border_color_dark', '#404040'),
			'bulletColorDark' => $get_color_option('anchorkit_toc_bullet_color_dark', '#7ec4ee'),
			'activeLinkColorLight' => $get_color_option('anchorkit_toc_active_link_color_light', '#00A0D2'),
			'activeLinkColorDark' => $get_color_option('anchorkit_toc_active_link_color_dark', '#5ba3d0'),
			'hoverBgColorLight' => $get_color_option('anchorkit_toc_hover_bg_color_light', 'rgba(0,0,0,0.04)'),
			'focusBgColorLight' => $get_color_option('anchorkit_toc_focus_bg_color_light', 'rgba(0,0,0,0.08)'),
			'hoverBgColorDark' => $get_color_option('anchorkit_toc_hover_bg_color_dark', 'rgba(255,255,255,0.08)'),
			'focusBgColorDark' => $get_color_option('anchorkit_toc_focus_bg_color_dark', 'rgba(255,255,255,0.12)'),
			// Shadows
			'boxShadowLight' => $get_string_option('anchorkit_toc_box_shadow_light', '0 4px 6px rgba(0, 0, 0, 0.1)'),
			'boxShadowDark' => $get_string_option('anchorkit_toc_box_shadow_dark', '0 2px 8px rgba(0, 0, 0, 0.3)'),
		);

		if ($defaults['maxHeadingDepth'] < $defaults['minHeadingDepth']) {
			$defaults['maxHeadingDepth'] = $defaults['minHeadingDepth'];
		}

		// 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()) {
				// Pro behavior settings
				$defaults['sticky'] = $get_bool_option('anchorkit_toc_sticky_enabled', false);
				$defaults['stickyPosition'] = $sanitize_choice($get_string_option('anchorkit_toc_sticky_position', 'content'), array('content', 'left', 'right'), 'content');
				$defaults['stickyOffset'] = max(0, $get_int_option('anchorkit_toc_sticky_offset', 20));
				$defaults['scrollSpy'] = $get_bool_option('anchorkit_toc_scroll_spy', true);
				$defaults['backToTopLink'] = $get_bool_option('anchorkit_toc_back_to_top_link', false);
				// Pro appearance settings
				$defaults['advancedTypographyOverride'] = $get_bool_option('anchorkit_toc_advanced_typography_override', false);
				// Pro metadata settings
				$defaults['showReadingTime'] = $get_bool_option('anchorkit_toc_show_reading_time', false);
				$defaults['showWordCount'] = $get_bool_option('anchorkit_toc_show_word_count', false);
				// Pro integrations
				$defaults['acfEnabled'] = $get_bool_option('anchorkit_toc_acf_enabled', false);
				$acf_field_names_pro = anchorkit_get_option('anchorkit_toc_acf_field_names', '');
				$defaults['acfFieldNames'] = is_string($acf_field_names_pro) ? $acf_field_names_pro : '';
				$acf_merge_mode_pro = anchorkit_get_option('anchorkit_toc_acf_merge_mode', 'after');
				$defaults['acfMergeMode'] = $sanitize_choice($acf_merge_mode_pro, array('before', 'after', 'replace'), 'after');
				$defaults['ampEnabled'] = $get_bool_option('anchorkit_toc_amp_enabled', false);
				$defaults['schemaEnabled'] = $get_bool_option('anchorkit_toc_schema_enabled', false);
				// Pro custom labels
				$custom_labels_pro = anchorkit_get_option('anchorkit_toc_custom_labels', '');
				$defaults['customLabels'] = is_string($custom_labels_pro) ? $custom_labels_pro : '';
			}
		}

		$cached_defaults = $defaults;
		return $cached_defaults;
	}
}
