<?php
/**
 * Helper functions to handle null values and prevent PHP deprecation warnings
 * 
 * @link       https://pinnerpress.com
 * @since      0.1.0
 *
 * @package    PinnerPress
 */

// If this file is called directly, abort.
if (!defined('WPINC')) {
    die;
}

/**
 * Initialize null safety filters
 * 
 * @since 0.1.0
 */
function pinnerpress_init_null_safety_filters() {
    // Guard: this function is hooked on muplugins_loaded, plugins_loaded, init,
    // AND called directly — but filters must only be registered once.  Without
    // this guard, ~20 filters stack 4-deep, adding 4 extra function calls to
    // every get_option(), home_url(), site_url(), etc. across the entire site.
    static $done = false;
    if ( $done ) {
        return;
    }
    $done = true;

    // Add pre_option filter to catch ALL options before they're used
    add_filter('pre_option', 'pinnerpress_pre_option_null_check', 1, 3);
    
    // Fix admin title to prevent null values
    add_filter('admin_title', 'pinnerpress_sanitize_admin_title', 10, 2);
    
    // Fix document title parts to prevent null values
    add_filter('document_title_parts', 'pinnerpress_sanitize_title_parts', 10, 1);
    
    // Fix wp_title to prevent null values
    add_filter('wp_title', 'pinnerpress_sanitize_wp_title', 10, 3);
    
    // Fix script URLs to prevent null values
    add_filter('script_loader_src', 'pinnerpress_sanitize_asset_url', 10, 2);
    
    // Fix style URLs to prevent null values
    add_filter('style_loader_src', 'pinnerpress_sanitize_asset_url', 10, 2);
    
    // Fix option values to prevent null values
    add_filter('option_pinnerpress_pinterest_url', 'pinnerpress_sanitize_option_value', 10, 2);
    add_filter('option_pinnerpress_pinterest_display_name', 'pinnerpress_sanitize_option_value', 10, 2);
    add_filter('option_pinnerpress_account_description', 'pinnerpress_sanitize_option_value', 10, 2);
    add_filter('option_pinnerpress_header_image', 'pinnerpress_sanitize_option_value', 10, 2);
    add_filter('option_pinnerpress_profile_image', 'pinnerpress_sanitize_option_value', 10, 2);
    
    // Fix Freemius-related options that might cause null warnings
    add_filter('option_fs_active_plugins', 'pinnerpress_sanitize_option_value', 10, 2);
    add_filter('pre_option_fs_active_plugins', 'pinnerpress_sanitize_pre_option_value', 10, 2);
    
    // Add global filter for get_option to catch any missed null values
    add_filter('option_', 'pinnerpress_global_option_sanitizer', 1, 2);
    
    // WordPress internal filters that might pass null values
    add_filter('home_url', 'pinnerpress_sanitize_url', 1, 4);
    add_filter('site_url', 'pinnerpress_sanitize_url', 1, 4);
    add_filter('admin_url', 'pinnerpress_sanitize_url', 1, 3);
    add_filter('plugins_url', 'pinnerpress_sanitize_url', 1, 3);
    add_filter('content_url', 'pinnerpress_sanitize_url', 1, 1);
    add_filter('network_home_url', 'pinnerpress_sanitize_url', 1, 3);
    add_filter('network_site_url', 'pinnerpress_sanitize_url', 1, 3);
    
    // Filter URLs in wp_nonce_url which might receive null
    add_filter('nonce_url', 'pinnerpress_sanitize_url', 1, 2);

    // Add filter for wp_is_stream to prevent null path errors
    add_filter('pre_wp_is_stream', 'pinnerpress_pre_wp_is_stream', 1, 1);
}
// Hook very early, before WordPress starts processing
add_action('plugins_loaded', 'pinnerpress_init_null_safety_filters', 1);
add_action('init', 'pinnerpress_init_null_safety_filters', 1);

// Also hook on muplugins_loaded for even earlier execution
add_action('muplugins_loaded', 'pinnerpress_init_null_safety_filters', 1);

// Hook immediately when this file is loaded
pinnerpress_init_null_safety_filters();

/**
 * Pre-option filter to prevent null values from being returned
 * 
 * @since 0.1.0
 * @param mixed $pre_option The pre_option value
 * @param string $option Option name
 * @param mixed $default Default value
 * @return mixed Filtered value
 */
function pinnerpress_pre_option_null_check($pre_option, $option, $default) {
    // Don't interfere with false returns which mean "continue processing"
    if ($pre_option === false) {
        return $pre_option;
    }
    
    // If the value is null, return false to let WordPress continue processing
    // but set a filter on the actual option to ensure it's not null
    if (is_null($pre_option)) {
        add_filter("option_{$option}", function($value) use ($default) {
            return is_null($value) ? (is_null($default) ? '' : $default) : $value;
        }, 1);
        return false;
    }
    
    return $pre_option;
}

/**
 * Sanitize admin title to prevent null values
 * 
 * @since 0.1.0
 * @param string $admin_title The admin title
 * @param string $title The page title
 * @return string Sanitized admin title
 */
function pinnerpress_sanitize_admin_title($admin_title, $title) {
    if (is_null($admin_title) || $admin_title === false) {
        return is_null($title) || $title === false ? 'PinnerPress' : (string)$title;
    }
    return (string)$admin_title;
}

/**
 * Sanitize document title parts to prevent null values
 * 
 * @since 0.1.0
 * @param array $title_parts The title parts
 * @return array Sanitized title parts
 */
function pinnerpress_sanitize_title_parts($title_parts) {
    if (is_array($title_parts)) {
        foreach ($title_parts as $key => $value) {
            if (is_null($value) || $value === false) {
                $title_parts[$key] = '';
            }
        }
    }
    return $title_parts;
}

/**
 * Sanitize wp_title to prevent null values
 * 
 * @since 0.1.0
 * @param string $title The title
 * @param string $sep The separator
 * @param string $seplocation The separator location
 * @return string Sanitized title
 */
function pinnerpress_sanitize_wp_title($title, $sep = '', $seplocation = '') {
    if (is_null($title) || $title === false) {
        return '';
    }
    return (string)$title;
}

/**
 * Sanitize asset URLs to prevent null values
 * 
 * @since 0.1.0
 * @param string $url The asset URL
 * @param string $handle The asset handle
 * @return string Sanitized URL
 */
function pinnerpress_sanitize_asset_url($url, $handle) {
    if (is_null($url) || $url === false) {
        return '';
    }
    return (string)$url;
}

/**
 * Sanitize option values to prevent null values
 * 
 * @since 0.1.0
 * @param mixed $value The option value
 * @param string $option The option name
 * @return mixed Sanitized value
 */
function pinnerpress_sanitize_option_value($value, $option) {
    if (is_null($value)) {
        return '';
    }
    return $value;
}

/**
 * Get option with null safety
 * 
 * This function wraps get_option() and ensures that null values are converted to empty strings
 * to prevent PHP 8.1+ deprecation warnings when the value is used in string functions.
 * 
 * @since 0.1.0
 * @param string $option Option name
 * @param mixed $default Default value if option doesn't exist
 * @return mixed Option value, with null converted to empty string
 */
function pinnerpress_get_option($option, $default = '') {
    $value = get_option($option, $default);
    
    // If the value is null, return the default or empty string
    if (is_null($value)) {
        return $default !== '' ? $default : '';
    }
    
    return $value;
}

/**
 * Sanitize URL to ensure it's never null
 * 
 * @since 0.1.0
 * @param string|null $url URL to sanitize
 * @param mixed ...$args Additional arguments passed by WordPress filters
 * @return string Sanitized URL, empty string if null
 */
function pinnerpress_sanitize_url($url, ...$args) {
    if (is_null($url) || $url === false) {
        return '';
    }
    return (string) $url;
}

/**
 * Sanitize text to ensure it's never null
 * 
 * @since 0.1.0
 * @param string|null $text Text to sanitize
 * @return string Sanitized text, empty string if null
 */
function pinnerpress_sanitize_text($text) {
    if (is_null($text) || $text === false) {
        return '';
    }
    return (string) $text;
}

/**
 * Sanitize pre_option values to prevent null values
 * 
 * @since 0.1.0
 * @param mixed $value The pre_option value
 * @param string $option The option name
 * @return mixed Sanitized value
 */
function pinnerpress_sanitize_pre_option_value($value, $option) {
    if (is_null($value)) {
        return array(); // Return empty array for Freemius options
    }
    return $value;
}

/**
 * Global option sanitizer to catch any missed null values
 * 
 * @since 0.1.0
 * @param mixed $value The option value
 * @param string $option The option name
 * @return mixed Sanitized value
 */
function pinnerpress_global_option_sanitizer($value, $option) {
    // Only process if value is null and it's a string-related option
    if (is_null($value) && (
        strpos($option, 'url') !== false ||
        strpos($option, 'title') !== false ||
        strpos($option, 'name') !== false ||
        strpos($option, 'description') !== false ||
        strpos($option, 'text') !== false
    )) {
        return '';
    }
    return $value;
}

/**
 * Pre-filter for wp_is_stream to prevent null path errors
 *
 * @since 0.1.0
 * @param string|null $path The path to check
 * @return bool|null False if path is null, null to continue processing
 */
function pinnerpress_pre_wp_is_stream($path) {
    if (is_null($path)) {
        return false;
    }
    return null;
}

/**
 * Get the standardized upgrade notification HTML for free users
 *
 * @since    0.6.8
 * @return   string    HTML for standardized upgrade notification
 */
function pinnerpress_get_upgrade_notification() {
    // Check if user is premium
    $is_premium = function_exists('pinnerpress_is_premium') ? pinnerpress_is_premium() : false;
    if ($is_premium) {
        return '';
    }

    ob_start();
    ?>
    <div class="pinnerpress-analytics-limitation notice notice-info">
        <h4><?php esc_html_e('🚀 Unlock PinnerPress Premium', 'pinnerpress'); ?></h4>
        <p><?php esc_html_e('Upgrade to premium to unlock advanced features including: Call-out Banners, Image Control, Custom CTA Banners, Follow Buttons, Rich Pins, Hidden Pins, Custom Descriptions, Repin Attribution, Post Analytics, and Image Analytics', 'pinnerpress'); ?></p>
        <a href="<?php echo esc_url(pinnerpress_get_upgrade_url()); ?>" class="button button-primary" target="_blank"><?php esc_html_e('Upgrade to Premium', 'pinnerpress'); ?></a>
    </div>
    <?php
    return ob_get_clean();
}

/**
 * Get the upgrade banner HTML for free users (legacy function - now uses standardized notification)
 *
 * @since    0.6.8
 * @return   string    HTML for upgrade banner
 */
function pinnerpress_get_upgrade_banner() {
    return pinnerpress_get_upgrade_notification();
}

/**
 * Get the detailed upgrade banner HTML for activation notices (legacy function - now uses standardized notification)
 *
 * @since    0.6.8
 * @return   string    HTML for detailed upgrade banner
 */
function pinnerpress_get_detailed_upgrade_banner() {
    return pinnerpress_get_upgrade_notification();
}