<?php
/**
 * The public-facing functionality of the plugin.
 *
 * @link       https://en.mementor.no/wordpress-plugins/
 * @since      1.1.0
 *
 * @package    TTSWP
 * @subpackage Mementor_TTS/public
 */

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

/**
 * The public-facing functionality of the plugin.
 */
class Mementor_TTS_Public {

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

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

    /**
     * The text domain of this plugin.
     *
     * @since    1.1.0
     * @access   private
     * @var      string    $text_domain    The text domain for internationalization.
     */
    private $text_domain;

    /**
     * The position of the player.
     *
     * @since    1.1.0
     * @access   private
     * @var      string    $player_position    The position of the player (before_title, after_title, or after_content).
     */
    private $player_position;

    /**
     * Store whether the automatic player has been added to avoid duplication
     */
    private $automatic_player_added = false;

    /**
     * Store whether the shortcode player has been added to avoid duplication
     */
    private $shortcode_player_added = false;

    /**
     * Static flag to track audio generation attempts
     */
    private static $audio_generation_attempted = array();
    
    /**
     * Player position manager instance
     * @var Mementor_TTS_Player_Position_Manager
     */
    private $position_manager;

    /**
     * Initialize the class and set its properties.
     *
     * @since    1.1.0
     * @param      string    $plugin_name       The name of the plugin.
     * @param      string    $version    The version of this plugin.
     */
    public function __construct($plugin_name, $version) {
        $this->plugin_name = 'text-to-speech-tts';
        $this->version = $version;
        $this->text_domain = 'text-to-speech-tts';
        
        // Add shortcode for raw HTML
        add_shortcode('mementor_raw', array($this, 'raw_shortcode'));
        
        // Keep default wpautop behavior - don't interfere with it globally

        // Important: Add filters to prevent WordPress from modifying our HTML
        add_filter('safe_style_css', array($this, 'add_safe_style_css'));

        // DISABLED: These functions break Elementor and other page builders by injecting extra <p> tags
        // Prevent wpautop from processing our player HTML
        // add_filter('the_content', array($this, 'prevent_autop_on_player'), 1);

        // Add filter to prevent wpautop from processing our player HTML
        // add_filter('the_content', array($this, 'protect_player_html'), 1);
        
        // Auto-generation on page visit is gated by the "Auto-generate on publish" setting.
        // Without this check, every paid-plan page visit for a post without audio would
        // trigger synchronous generation — burning credits the user never opted into.
        add_filter('mementor_tts_auto_generation_enabled', function() {
            return ttswp_has_paid_plan() && get_option('mementor_tts_auto_generate_on_publish', '0') === '1';
        });

        // Log credit usage after auto-generation (AJAX handler has its own logging)
        add_action('mementor_tts_after_generate_audio', function($credits, $post_id, $voice_id) {
            if (wp_doing_ajax()) {
                return; // AJAX handler logs separately with more detailed metadata
            }
            $speech_builder = Mementor_TTS_Speech_Builder::get_instance();
            $speech_builder->log_generation($post_id, $credits, array(
                'text_length' => $credits,
                'voice_id'    => $voice_id,
                'model_id'    => get_option('mementor_tts_model', 'eleven_flash_v2_5'),
                'api_type'    => 'auto',
            ));
        }, 10, 3);

        // Clear dynamic CSS cache when player settings are updated
        add_action('update_option', array($this, 'maybe_clear_dynamic_css_cache'), 10, 3);
        
        // Add AudioObject schema markup if enabled and PRO is active
        add_action('wp_head', array($this, 'output_audio_schema'), 15);
        
        // Initialize position manager as singleton
        require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-mementor-tts-player-position-manager.php';
        $this->position_manager = Mementor_TTS_Player_Position_Manager::get_instance($this);
        if ($this->position_manager) {
            $this->position_manager->init();
        }
        
        // Load Elementor CSS if needed
        add_action('wp_enqueue_scripts', function() {
            if (is_singular() && defined('ELEMENTOR_VERSION')) {
                $post_id = get_the_ID();
                if ($post_id && get_post_meta($post_id, '_elementor_edit_mode', true)) {
                    wp_enqueue_style(
                        'mementor-tts-elementor',
                        plugin_dir_url(dirname(__FILE__)) . 'public/css/mementor-tts-elementor.css',
                        array('mementor-tts-public'),
                        $this->version
                    );
                }
            }
        });
    }

    /**
     * Process content to protect our player HTML
     */
    public function process_content($content) {
        // Don't process if we're using after_title_before_excerpt position
        if ($this->player_position === 'after_title_before_excerpt') {
            return $content;
        }

        return preg_replace_callback(
            '/<div class="mementor-tts-player-container.*?<\/div><\/div><\/div>/s',
            function($matches) {
                return '[mementor_raw]' . $matches[0] . '[/mementor_raw]';
            },
            $content
        );
    }

    /**
     * Handle raw HTML shortcode
     */
    public function raw_shortcode($atts, $content = '') {
        // Remove all p tags from the content
        $content = preg_replace('/<p\b[^>]*>(?:&nbsp;|\s)*<\/p>/', '', $content);
        $content = preg_replace('/<\/?p>/', '', $content);
        return $content;
    }

    /**
     * Add safe style attributes to WordPress allowed list
     */
    public function add_safe_style_css($styles) {
        $styles[] = 'display';
        return $styles;
    }

    /**
     * Prevent wpautop from processing our player HTML
     */
    public function prevent_autop_on_player($content) {
        // Don't process if we're using after_title_before_excerpt position
        if ($this->player_position === 'after_title_before_excerpt') {
            return $content;
        }

        // Find all player containers - use different delimiter to avoid escaping issues
        $pattern = '#(<div class="mementor-tts-player-container.*?</div></div></div>)#s';
        
        // Split content by player containers
        $pieces = preg_split($pattern, $content, -1, PREG_SPLIT_DELIM_CAPTURE);
        
        // Check if preg_split failed
        if ($pieces === false) {
            // Return original content if regex failed
            return $content;
        }
        
        // Process each piece
        foreach ($pieces as $i => $piece) {
            if (strpos($piece, 'mementor-tts-player-container') !== false) {
                // Wrap player HTML in noautop tags
                $pieces[$i] = '<!-- wp:html -->' . $piece . '<!-- /wp:html -->';
            }
        }
        
        return implode('', $pieces);
    }

    /**
     * Protect player HTML from wpautop
     */
    public function protect_player_html($content) {
        // Don't process if we're using after_title_before_excerpt position
        if ($this->player_position === 'after_title_before_excerpt') {
            return $content;
        }

        // First, save all player HTML blocks
        $blocks = array();
        if (preg_match_all('#<div class="mementor-tts-player-container.*?</div></div></div>#s', $content, $matches)) {
            foreach ($matches[0] as $i => $match) {
                $blocks[$i] = $match;
                $content = str_replace($match, "<!--mementor-player-$i-->", $content);
            }
        }
        
        // Let wpautop do its thing
        $content = wpautop($content);
        
        // Now restore all player blocks
        foreach ($blocks as $i => $block) {
            $content = str_replace("<!--mementor-player-$i-->", $block, $content);
        }
        
        return $content;
    }

    /**
     * Setup content filters
     * This method adds the necessary content filters for player insertion
     */
    public function setup_content_filters() {
        // Check if we're on a singular post
        if (!is_singular()) {
            return;
        }
        
        // Get supported post types
        $post_types = $this->get_supported_post_types();
        
        // Check if current post type is supported
        if (!in_array(get_post_type(), $post_types)) {
            return;
        }
        
        // Check if shortcode is used in post
        global $post;
        if ($post && has_shortcode($post->post_content, 'mementor-tts')) {
            // Ensure assets are loaded for shortcode
            add_filter('mementor_tts_should_load_assets', '__return_true');
            wp_enqueue_script('mementor-tts-shortcode');
        }

        // DISABLED: Old player insertion - now handled by position manager
        // $player_position = get_option('mementor_tts_player_position', 'before');
        // $content_priority = ($player_position === 'before') ? 10 : 15;
        // add_filter('the_content', array($this, 'maybe_add_player_to_content'), $content_priority);
    }

    /**
     * Inject player after title but before excerpt in Gutenberg blocks
     */
    public function inject_player_after_title_before_excerpt($block_content, $block) {
        // Only proceed if this is a post title block
        if ($block['blockName'] !== 'core/post-title') {
            return $block_content;
        }

        // Only proceed if we haven't added the automatic player yet
        if ($this->automatic_player_added) {
            // Only log once per page load
            static $logged = false;
            if (!$logged) {
                $this->log_debug('Automatic player already added, skipping additional block injections');
                $logged = true;
            }
            return $block_content;
        }

        // Only add player on singular posts/pages in main query
        if (!is_singular() || !in_the_loop() || !is_main_query()) {
            $this->log_debug('Not a singular post or not in main query, skipping Gutenberg injection');
            return $block_content;
        }

        // Get post ID and check if enabled
        $post_id = get_the_ID();
        $enabled_post_types = get_option('mementor_tts_post_types', array('post'));
        if (!in_array(get_post_type($post_id), $enabled_post_types)) {
            $this->log_debug('Post type not enabled, skipping Gutenberg injection');
            return $block_content;
        }

        // Get audio URL
        $audio_url = $this->get_audio_url($post_id);
        if (!$audio_url) {
            // Check if this is a PRO version or if auto-generation is enabled
            $is_pro = ttswp_has_paid_plan();
            $auto_generation_enabled = apply_filters('mementor_tts_auto_generation_enabled', false);
            
            // Only generate audio automatically if this is a PRO feature
            if ($is_pro && $auto_generation_enabled) {
                $this->generate_audio_for_post($post_id);
                $audio_url = $this->get_audio_url($post_id);
            }
            if (!$audio_url) {
                $this->log_debug('No audio URL available, skipping Gutenberg injection');
                return $block_content;
            }
        }

        $this->log_debug('Injecting player via Gutenberg block filter');
        
        // Mark automatic player as added
        $this->automatic_player_added = true;

        // Build player HTML with specific class for this position
        $player_html = '<div class="mementor-tts-player-container mementor-tts-automatic mementor-tts-gutenberg">';
        $player_html .= $this->render_player($audio_url, $post_id);
        $player_html .= '</div>';
        
        // Return the block content with the player appended
        return $block_content . $player_html;
    }

    /**
     * Output player after title
     */
    public function output_player_after_title() {
        $this->log_debug('Attempting to output player after title');
        
        // Only proceed if we haven't added the automatic player yet
        if ($this->automatic_player_added) {
            $this->log_debug('Automatic player already added, skipping');
            return;
        }

        // Only add player on singular posts/pages in main query
        if (!is_singular() || !in_the_loop() || !is_main_query()) {
            $this->log_debug('Not a singular post or not in main query, skipping');
            return;
        }

        // Check if this post type is enabled
        $post_id = get_the_ID();
        $enabled_post_types = get_option('mementor_tts_post_types', array('post'));
        if (!in_array(get_post_type($post_id), $enabled_post_types)) {
            $this->log_debug('Post type not enabled, skipping');
            return;
        }

        // Get audio URL
        $audio_url = $this->get_audio_url($post_id);
        if (!$audio_url) {
            // Check if this is a PRO version or if auto-generation is enabled
            $is_pro = ttswp_has_paid_plan();
            $auto_generation_enabled = apply_filters('mementor_tts_auto_generation_enabled', false);
            
            // Only generate audio automatically if this is a PRO feature
            if ($is_pro && $auto_generation_enabled) {
                $this->generate_audio_for_post($post_id);
                $audio_url = $this->get_audio_url($post_id);
            }
            if (!$audio_url) {
                $this->log_debug('Failed to generate audio URL');
                return;
            }
        }
        
        $this->log_debug('Successfully got audio URL: ' . $audio_url);
        
        // Mark automatic player as added
        $this->automatic_player_added = true;

        // Build player HTML with specific class for this position
        $player_html = '<div class="mementor-tts-player-container mementor-tts-after-title-before-excerpt">';
        $player_html .= $this->render_player($audio_url, $post_id);
        $player_html .= '</div>';
        
        $this->log_debug('Outputting player HTML');
        
        // Output the player
        echo wp_kses_post($player_html);
    }

    /**
     * Buffer output to inject player if theme doesn't support hooks
     */
    public function maybe_buffer_output() {
        // Only on singular pages
        if (!is_singular()) {
            return;
        }

        // Skip product pages when product-specific placement is configured
        if (is_singular('product') && class_exists('WooCommerce')) {
            $product_short = get_option('mementor_tts_product_player_short_desc', 'disabled');
            $product_long = get_option('mementor_tts_product_player_long_desc', 'before');
            if ($product_short !== 'disabled' || $product_long !== 'disabled') {
                return;
            }
        }

        // Check if this post type is enabled
        $post_id = get_the_ID();
        $enabled_post_types = get_option('mementor_tts_post_types', array('post'));
        if (!in_array(get_post_type($post_id), $enabled_post_types)) {
            return;
        }

        ob_start(array($this, 'inject_player_into_output'));
    }

    /**
     * Inject player into buffered output or filter content
     * Note: This method is used both as an ob_start callback and a the_content filter.
     */
    public function inject_player_into_output($content) {
        // Get the current post ID within the loop/filter context
        $post_id = get_the_ID();

        // If we couldn't get a post ID, return the original content
        if (empty($post_id)) {
            $this->log_debug('Could not get post ID in inject_player_into_output');
            return $content;
        }
        
        // Get player position setting
        // Note: This check might be redundant if only called via the specific filter case
        // but kept for safety if ob_start usage remains.
        $player_position = get_option('mementor_tts_player_position', 'after_content'); // Default changed to after_content
        
        // Get container classes
        $container_classes = $this->get_player_container_classes();
        
        // Get audio URL using the retrieved post_id
        $audio_url = $this->get_audio_url($post_id);
        if (!$audio_url) {
             $this->log_debug('No audio URL for post ' . $post_id . ' in inject_player_into_output');
             return $content; // Don't add player if no audio
        }
        
        // Build player HTML with container, using the retrieved post_id
        $player_html = '<div class="' . esc_attr(implode(' ', $container_classes)) . '" data-post-id="' . esc_attr($post_id) . '" data-player-type="auto-inserted">';
        $player_html .= $this->render_player($audio_url, $post_id);
        $player_html .= '</div>';
        
        // Add player based on position (Primarily for the 'after_content' case when used as a filter)
        // When used as an ob_start callback, the position might be different, but 
        // ob_start usage seems less likely with current setup.
        if ($player_position === 'before_title') { // Example check, adjust if needed
             // Potentially prepend if used differently, though unlikely now.
             return $player_html . $content; 
        } else { // Default to appending for 'after_content' filter or other cases
            return $content . $player_html;
        }
    }

    /**
     * Output player for shortcode or widget
     */
    public function output_player($atts = array()) {
        // Don't render player markup when extracting content for TTS.
        if (function_exists('ttswp_is_extracting_for_tts') && ttswp_is_extracting_for_tts()) {
            return '';
        }

        // Parse shortcode attributes
        $atts = shortcode_atts(
            array(
                'id' => null,
                'align' => 'left',
                'label' => '',
                'show_label' => '1',
            ),
            $atts,
            'mementor_tts'
        );

        // Get post ID
        $post_id = $atts['id'] ? intval($atts['id']) : get_the_ID();
        if (!$post_id) {
            return '';
        }

        // Get audio URL
        $audio_url = $this->get_audio_url($post_id);
        if (!$audio_url) {
            // Check if this is a PRO version or if auto-generation is enabled
            $is_pro = ttswp_has_paid_plan();
            $auto_generation_enabled = apply_filters('mementor_tts_auto_generation_enabled', false);
            
            // Only generate audio automatically if this is a PRO feature
            if ($is_pro && $auto_generation_enabled) {
                $this->generate_audio_for_post($post_id);
                $audio_url = $this->get_audio_url($post_id);
            }
            if (!$audio_url) {
                return '';
            }
        }

        // Set alignment class
        $align_class = 'mementor-tts-align-' . sanitize_html_class($atts['align']);

        // Override label settings if provided in shortcode
        if ($atts['label'] !== '') {
            add_filter('option_mementor_tts_player_label', function() use ($atts) {
                return $atts['label'];
            });
        }

        // Standardized approach for show_label handling
        add_filter('option_mementor_tts_show_player_label', function() use ($atts) {
            // Use the standardized check to ensure consistent behavior
            return ($atts['show_label'] === '1' || $atts['show_label'] === 1 || $atts['show_label'] === true) ? '1' : '0';
        });

        // Render player
        $player_html = '<div class="mementor-tts-shortcode-player ' . esc_attr($align_class) . '" data-post-id="' . esc_attr($post_id) . '" data-player-type="shortcode">';
        $player_html .= $this->render_player($audio_url, 'shortcode-' . $post_id);
        $player_html .= '</div>';

        return $player_html;
    }

    /**
     * Get audio URL for a post
     */
    public function get_audio_url($post_id) {
        global $wpdb;

        // First check database for S3 URL if Media Offload is enabled
        $media_offload_enabled = get_option('mementor_tts_s3_enabled', '0') === '1';

        if ($media_offload_enabled) {
            $table_name = $wpdb->prefix . 'mementor_tts_speeches';
            $speech = $wpdb->get_row($wpdb->prepare(
                "SELECT s3_url, file_url FROM {$table_name} WHERE post_id = %d ORDER BY generated_date DESC LIMIT 1",
                $post_id
            ));

            if ($speech) {
                // Prefer S3 URL if available
                if (!empty($speech->s3_url)) {
                    $this->log_debug('Found S3 URL for post ' . $post_id . ': ' . $speech->s3_url);
                    return $speech->s3_url;
                }
                // Fall back to file_url from database
                if (!empty($speech->file_url)) {
                    $this->log_debug('Found file URL for post ' . $post_id . ': ' . $speech->file_url);
                    return $speech->file_url;
                }
            }
        }

        // Get WordPress upload directory information
        $upload_dir = wp_upload_dir();
        $audio_dir = $upload_dir['basedir'] . '/text-to-speech-tts/';

        // Get current language code - use I18n Helper if available (for Weglot, WPML, etc.)
        $language_code = 'en'; // Default to English
        if (class_exists('Mementor_TTS_I18n_Helper')) {
            $language_code = Mementor_TTS_I18n_Helper::get_current_language();
            $this->log_debug('Language detected via I18n Helper: ' . $language_code);
        } elseif (defined('ICL_LANGUAGE_CODE') && !empty(ICL_LANGUAGE_CODE)) {
            $language_code = ICL_LANGUAGE_CODE;
        } else {
            // Use the correct option name that matches the voices settings
            $language_code = get_option('mementor_tts_language', 'en');
        }

        // Ensure language code is not empty
        if (empty($language_code)) {
            $language_code = 'en';
        }

        // Only look for the file with the current language
        // Do NOT fall back to other language files - this ensures each language gets its own audio

        // Check post meta first — this is the authoritative source for audio URLs.
        // Try language-specific key first, then generic. Verify the file exists on disk
        // to handle stale meta from renames or deletions.
        $meta_candidates = array(
            get_post_meta($post_id, '_mementor_tts_audio_url_' . $language_code, true),
            get_post_meta($post_id, '_mementor_tts_audio_url', true),
        );
        foreach ($meta_candidates as $meta_url) {
            if (empty($meta_url)) {
                continue;
            }
            // External URLs (CDN, S3, CloudFront) — return directly, no file existence check needed
            $site_host = wp_parse_url(site_url(), PHP_URL_HOST);
            $meta_host = wp_parse_url($meta_url, PHP_URL_HOST);
            if ($meta_host && $meta_host !== $site_host) {
                $this->log_debug('Found external audio URL in post meta for post ' . $post_id . ': ' . $meta_url);
                return $meta_url;
            }
            // Local file — derive disk path from the URL itself rather than
            // assuming a specific subdirectory. Free-plan downloads written by
            // 3.1.0–3.2.13 live under /uploads/tts/; new free-plan downloads
            // and all paid-plan/shortcode audio live under /uploads/text-to-speech-tts/.
            // Both must resolve through the same code path.
            $meta_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $meta_url);
            if ($meta_path !== $meta_url && file_exists($meta_path)) {
                $this->log_debug('Found audio via post meta for post ' . $post_id . ': ' . $meta_url);
                return $meta_url;
            }
        }

        // Filesystem fallback for legacy installs without post meta. Search the
        // canonical /text-to-speech-tts/ directory first, then the pre-3.2.14
        // free-plan /uploads/tts/ directory so cleared-meta installs still play.
        $possible_files = array(
            'mementor-' . $post_id . '-' . $language_code . '.mp3',
            'post-' . $post_id . '-' . $language_code . '.mp3',
        );

        if (class_exists('Mementor_TTS_I18n_Helper')) {
            $original_language = Mementor_TTS_I18n_Helper::get_original_language();
            if ($language_code === $original_language) {
                $possible_files[] = 'post-' . $post_id . '.mp3';
            }
        } else {
            $possible_files[] = 'post-' . $post_id . '.mp3';
        }

        $this->log_debug('Audio detection for post ' . $post_id . ' using language: ' . $language_code);

        foreach ($possible_files as $filename) {
            $audio_file = $audio_dir . $filename;
            if (file_exists($audio_file)) {
                $this->log_debug('Found audio file via filesystem: ' . $filename);
                return $upload_dir['baseurl'] . '/text-to-speech-tts/' . $filename;
            }
        }

        // Pre-3.2.14 free-plan downloads: tts-{post_id}-{timestamp}.mp3 under
        // /uploads/tts/. Filename has no language code, so this fallback only
        // fires when the current language matches the site's original language —
        // otherwise we'd leak (e.g.) English audio onto a Norwegian render whose
        // meta was cleared. Same guard the /text-to-speech-tts/ post-{id}.mp3
        // fallback uses above.
        $saas_fallback_ok = true;
        if (class_exists('Mementor_TTS_I18n_Helper')) {
            $saas_fallback_ok = ($language_code === Mementor_TTS_I18n_Helper::get_original_language());
        }
        if ($saas_fallback_ok) {
            $saas_dir = trailingslashit($upload_dir['basedir']) . 'tts/';
            if (is_dir($saas_dir)) {
                $matches = glob($saas_dir . 'tts-' . (int) $post_id . '-*.mp3');
                if (!empty($matches)) {
                    $filename = basename($matches[0]);
                    $this->log_debug('Found legacy free-plan audio via /tts/ fallback: ' . $filename);
                    return $upload_dir['baseurl'] . '/tts/' . $filename;
                }
            }
        }

        $this->log_debug('No audio file found for post ' . $post_id . ' in language ' . $language_code);
        return '';
    }

    /**
     * Generate audio for a post
     */
    private function generate_audio_for_post($post_id) {
        // Check if we've already attempted generation for this post in this request
        if (isset(self::$audio_generation_attempted[$post_id])) {
            return;
        }

        // Mark that we've attempted generation for this post
        self::$audio_generation_attempted[$post_id] = true;

        // Check if a previous generation attempt failed recently (6-hour cooldown)
        // This prevents retrying on every page load for posts with problematic content
        $fail_key = 'mementor_tts_gen_fail_' . $post_id;
        if (get_transient($fail_key)) {
            $this->log_debug('Skipping auto-generation for post ' . $post_id . ' — recent failure cooldown active');
            return;
        }

        // Get post content
        $post = get_post($post_id);
        if (!$post) {
            $this->log_debug('Post not found for ID ' . $post_id, 'error');
            return;
        }

        // Setup post data to ensure template tags work correctly
        setup_postdata($post);

        // Get post title and content
        $title = $post->post_title;
        $content = $post->post_content;

        // Detect raw Elementor JSON data in post_content.
        // When Elementor stores content, post_content may contain the raw JSON
        // data structure instead of rendered HTML. We need to extract the actual
        // text content from _elementor_data post meta instead.
        if (strpos($content, '"elType"') !== false) {
            $this->log_debug('Raw Elementor JSON detected in post_content for post ' . $post_id . ' - extracting text from _elementor_data');
            $elementor_data_json = get_post_meta($post_id, '_elementor_data', true);
            if (!empty($elementor_data_json)) {
                $elementor_data = json_decode($elementor_data_json, true);
                if (is_array($elementor_data)) {
                    $elementor_html = $this->extract_text_from_elementor_data($elementor_data);
                    if (!empty($elementor_html)) {
                        $content = $elementor_html;
                        $this->log_debug('Extracted Elementor text content, length: ' . strlen($content));
                    }
                }
            }
        }

        // Prepare text for TTS
        $text = '';

        // Add title if enabled
        $include_title = get_option('mementor_tts_include_title', true);
        if ($include_title) {
            $text .= '--- ' . $title;
            if ($post->post_author) {
                $author = get_the_author_meta('display_name', $post->post_author);
                $text .= ' -- By ' . $author;
            }
            $text .= ' -- ';
        }

        // Add excerpt if enabled in settings
        $include_excerpt = (bool) get_option('mementor_tts_include_excerpt', false);
        if ($include_excerpt && has_excerpt($post_id)) {
            $excerpt = get_the_excerpt();
            $excerpt = wp_strip_all_tags($excerpt);
            $excerpt = str_replace('&nbsp;', ' ', $excerpt);
            $excerpt = preg_replace('/\s+/', ' ', $excerpt);
            $excerpt = trim($excerpt);
            if (!empty($excerpt)) {
                $text .= $excerpt . ' -- ';
            }
        }

        // Process content using CSS selectors if processor is available
        if (!class_exists('Mementor_TTS_Processor')) {
            require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-processor.php';
        }
        $processor = Mementor_TTS_Processor::get_instance();
        if ($processor && method_exists($processor, 'get_content_from_html')) {
            // Use the processor's method to extract content with CSS selectors
            $content = $processor->get_content_from_html($content);
        } else {
            // Fallback to simple tag stripping
            $content = wp_strip_all_tags($content);
        }
        
        // Clean up the extracted content
        $content = str_replace('&nbsp;', ' ', $content);
        $content = preg_replace('/\s+/', ' ', $content);
        $content = trim($content);
        
        // Clean up empty parts
        $content_parts = explode(' -- ', $content);
        $content_parts = array_filter(array_map('trim', $content_parts)); // Remove empty parts
        // REMOVED array_unique() - it was removing duplicate paragraphs in Fusion Builder posts
        $content = implode(' -- ', $content_parts);
        
        $text .= $content;

        // Reset post data
        wp_reset_postdata();

        // Initialize the processor and generate audio
        require_once plugin_dir_path(__FILE__) . 'class-mementor-tts-processor.php';
        $processor = Mementor_TTS_Processor::get_instance();
        
        // Remove any existing speak tags to avoid double processing
        $text = preg_replace('#</?speak>#', '', $text);
        
        // Add SSML tags
        $text = '<speak><break time="0.65s" />' . $text . '</speak>';
        
        $this->log_debug('Text being sent to API: ' . $text);

        $ttswp_pub_text_len = strlen( $text );
        $ttswp_pub_raw_len  = isset( $post ) && is_object( $post ) ? strlen( (string) $post->post_content ) : 0;
        ttswp_send_remote_debug_event(
            'content_extracted',
            sprintf( 'public frontend path length: %d (raw %d)', $ttswp_pub_text_len, $ttswp_pub_raw_len ),
            array(
                'path'         => 'public.frontend_generation',
                'text_len'     => $ttswp_pub_text_len,
                'raw_post_len' => $ttswp_pub_raw_len,
            ),
            $ttswp_pub_text_len < 500 && $ttswp_pub_raw_len > 1500 ? 'warning' : 'debug',
            $post_id
        );

        $result = $processor->generate_audio($text, $post_id);

        if ($result && is_string($result)) {
            $this->log_debug('Audio generated successfully: ' . $result);
        } else {
            $this->log_debug('Failed to generate audio for post ' . $post_id . ' — setting 6-hour cooldown');
            set_transient($fail_key, time(), 6 * HOUR_IN_SECONDS);
        }
    }

    /**
     * Filter callback to determine if assets should be loaded
     *
     * @since    1.0.0
     * @param    bool    $should_load    Current filter value
     * @return   bool                    Whether assets should be loaded
     */
    public function filter_should_load_assets($should_load) {
        // If already true (e.g., from shortcode), don't override
        if ($should_load) {
            return $should_load;
        }
        
        // Check if we're on a singular page with shortcode
        if (is_singular()) {
            global $post;
            if ($post && (has_shortcode($post->post_content, 'tts_player') || has_shortcode($post->post_content, 'mementor_tts'))) {
                return true;
            }
        }
        
        // Use our internal check
        return $this->should_load_assets();
    }

    /**
     * Register and enqueue the stylesheets for the public-facing side of the site.
     *
     * @since    1.0.0
     */
    public function enqueue_styles() {
        // Only proceed if we're on a public-facing page
        if (is_admin()) {
            return;
        }

        // Only enqueue if we should load assets or we're processing a shortcode
        if ($this->should_load_assets() || doing_filter('shortcode_atts_mementor_tts')) {
            // Force load dashicons on frontend if not already loaded
            if (!wp_style_is('dashicons', 'enqueued')) {
                wp_enqueue_style('dashicons');
            }
            
            // Enqueue our shared styles with dashicons as a dependency
            wp_enqueue_style(
                'mementor-tts-shared', 
                MEMENTOR_TTS_PLUGIN_URL . 'public/css/mementor-tts-shared.css', 
                array('dashicons'), // Explicitly add dashicons dependency
                $this->version,
                'all'
            );
            
            // Data attributes are now added by class-mementor-tts-css-compatibility.php
            
            // Add dynamic CSS variables only if the stylesheet is enqueued
            if (wp_style_is('mementor-tts-shared', 'enqueued')) {
                $this->add_dynamic_css();
            }
        }
    }

    /**
     * Add dynamic CSS variables based on plugin settings
     *
     * @since    1.0.0
     */
    private function add_dynamic_css() {
        static $dynamic_css_added = false;
        
        // Only add once per page load
        if ($dynamic_css_added) {
            return;
        }

        // Get dynamic CSS variables
        $dynamic_css = $this->get_dynamic_css_variables();
        
        // Add inline styles if dynamic CSS is not empty
        if (!empty($dynamic_css)) {
            // Sanitize the CSS before adding it inline
            $safe_css = wp_strip_all_tags($dynamic_css);
            wp_add_inline_style('mementor-tts-shared', $safe_css);
        }
        
        // Mark as added to prevent duplicate additions
        $dynamic_css_added = true;
    }

    /**
     * Get dynamic CSS variables based on plugin settings
     *
     * @since    1.0.0
     * @return string CSS variables
     */
    private function get_dynamic_css_variables() {
        // Try to get cached CSS variables first
        $cached_css = get_transient('mementor_tts_dynamic_css');
        if ($cached_css !== false) {
            return $cached_css;
        }

        // Get all player settings
        $label_margin = absint(get_option('mementor_tts_player_label_margin', '10'));
        $label_size = absint(get_option('mementor_tts_player_label_size', '14'));
        $label_weight = absint(get_option('mementor_tts_player_label_weight', '400'));
        $label_color = sanitize_hex_color(get_option('mementor_tts_player_label_color', '#1d2327'));
        
        $bg_color = sanitize_hex_color(get_option('mementor_tts_player_bg_color', '#f6f7fb'));
        $border_color = sanitize_hex_color(get_option('mementor_tts_player_border_color', '#dcdcde'));
        $text_color = sanitize_hex_color(get_option('mementor_tts_player_text_color', '#0e0e0f'));
        $accent_color = sanitize_hex_color(get_option('mementor_tts_player_accent_color', '#2271b1'));
        $play_button_bg = sanitize_hex_color(get_option('mementor_tts_play_button_bg', '#ffffff'));
        $timer_color = sanitize_hex_color(get_option('mementor_tts_timer_color', '#1d2327'));
        $progress_bar_default = sanitize_hex_color(get_option('mementor_tts_progress_bar_default', '#e0e0e0'));
        $progress_bar_playing = sanitize_hex_color(get_option('mementor_tts_progress_bar_playing', '#2271b1'));
        
        $play_icon_size = absint(get_option('mementor_tts_play_icon_size', '24'));
        $font_size = absint(get_option('mementor_tts_font_size', '14'));
        $player_padding = absint(get_option('mementor_tts_player_padding', '12'));
        $player_opacity = floatval(get_option('mementor_tts_player_opacity', '1'));

        // Convert bg color + opacity to rgba for sticky footer background-only opacity
        $sticky_bg_rgba = $bg_color;
        if ( $player_opacity < 1 && preg_match('/^#([a-f0-9]{6})$/i', $bg_color, $m) ) {
            $r = hexdec( substr( $m[1], 0, 2 ) );
            $g = hexdec( substr( $m[1], 2, 2 ) );
            $b = hexdec( substr( $m[1], 4, 2 ) );
            $sticky_bg_rgba = "rgba({$r}, {$g}, {$b}, {$player_opacity})";
        }

        // Get default max-width settings for generating CSS
        $default_max_width = absint(get_option('mementor_tts_player_max_width', 100));
        $default_max_width_unit = get_option('mementor_tts_player_max_width_unit', '%');

        // Base CSS with core variables
        $css = "
            :root {
                --mementor-tts-label-margin: {$label_margin}px;
                --mementor-tts-label-size: {$label_size}px;
                --mementor-tts-label-weight: {$label_weight};
                --mementor-tts-label-color: {$label_color};
                --mementor-tts-custom-label-color: {$label_color};
                --mementor-tts-bg-color: {$bg_color};
                --mementor-tts-border-color: {$border_color};
                --mementor-tts-text-color: {$text_color};
                --mementor-tts-accent-color: {$accent_color};
                --mementor-tts-play-button-bg: {$play_button_bg};
                --mementor-tts-timer-color: {$timer_color};
                --mementor-tts-progress-default: {$progress_bar_default};
                --mementor-tts-progress-playing: {$progress_bar_playing};
                --mementor-tts-play-icon-size: {$play_icon_size}px;
                --mementor-tts-font-size: {$font_size}px;
                --mementor-tts-player-padding: {$player_padding}px;
                --mementor-tts-player-opacity: {$player_opacity};
                --mementor-tts-sticky-bg: {$sticky_bg_rgba};
                --mementor-tts-max-width: {$default_max_width}{$default_max_width_unit};
            }

            /* Ensure custom label color is applied to elements */
            .mementor-tts-player-label.label-color-custom {
                color: var(--mementor-tts-custom-label-color);
            }

            /* Ensure custom label color is applied when set via data attribute */
            .mementor-tts-player-label[data-custom-color] {
                color: var(--mementor-tts-custom-label-color);
            }
        ";       

        // Cache the CSS for 12 hours
        set_transient('mementor_tts_dynamic_css', $css, 12 * HOUR_IN_SECONDS);
        
        return $css;
    }

    /**
     * Check if we should load assets on this page
     *
     * @since    1.0.0
     * @return boolean True if assets should be loaded
     */
    private function should_load_assets() {
        // Don't load on non-singular pages
        if (!is_singular()) {
            $this->log_debug('Not a singular page - skipping assets');
            return false;
        }

        $post_id = get_the_ID();
        $post = $post_id ? get_post($post_id) : null;

        $this->log_debug('should_load_assets check for post ' . $post_id . ':');

        // Shortcode anywhere in the post: always load, regardless of post-type enablement.
        if ($post && (has_shortcode($post->post_content, 'tts_player') || has_shortcode($post->post_content, 'mementor-tts'))) {
            $this->log_debug('- Found TTS shortcode in content');
            $this->log_debug('- Should load assets: YES');
            return true;
        }

        // Auto-injection paths only matter when post type is enabled.
        $enabled_post_types = (array) get_option('mementor_tts_post_types', array('post'));
        $current_post_type = get_post_type($post_id);
        $this->log_debug('- Current post type: ' . $current_post_type);
        $this->log_debug('- Enabled post types: ' . print_r($enabled_post_types, true));
        if (!in_array($current_post_type, $enabled_post_types, true)) {
            $this->log_debug('- Should load assets: NO');
            return false;
        }

        // Post already has audio (meta, speeches table, or filesystem): load.
        if ($this->post_has_audio($post_id)) {
            $this->log_debug('- Found audio for post');
            $this->log_debug('- Should load assets: YES');
            return true;
        }

        // No audio yet, but auto-generation may produce it during this render.
        if (ttswp_has_paid_plan() && apply_filters('mementor_tts_auto_generation_enabled', false)) {
            $this->log_debug('- Auto-generation may create audio during render');
            $this->log_debug('- Should load assets: YES');
            return true;
        }

        $this->log_debug('- No audio for this post, skipping assets');
        $this->log_debug('- Should load assets: NO');
        return false;
    }

    /**
     * Whether a post has TTS audio that the player would render.
     *
     * Mirrors get_audio_url() so the asset gate matches rendering reality:
     * post meta (language-specific then generic), the mementor_tts_speeches
     * table when Media Offload is enabled, and a filesystem fallback for
     * legacy installs where meta was never written. Matters for multilingual
     * setups (Weglot/WPML) where a post may have audio for one language but
     * not another, so we resolve language first.
     */
    private function post_has_audio($post_id) {
        if (!$post_id) {
            return false;
        }

        $language_code = 'en';
        if (class_exists('Mementor_TTS_I18n_Helper')) {
            $language_code = Mementor_TTS_I18n_Helper::get_current_language();
        } elseif (defined('ICL_LANGUAGE_CODE') && !empty(ICL_LANGUAGE_CODE)) {
            $language_code = ICL_LANGUAGE_CODE;
        } else {
            $language_code = get_option('mementor_tts_language', 'en');
        }
        if (empty($language_code)) {
            $language_code = 'en';
        }

        if (get_post_meta($post_id, '_mementor_tts_audio_url_' . sanitize_key($language_code), true)) {
            return true;
        }
        if (get_post_meta($post_id, '_mementor_tts_audio_url', true)) {
            return true;
        }

        // Legacy installs and Media Offload sites can have audio without post
        // meta: the file lives in the speeches table or on disk only.
        if (get_option('mementor_tts_s3_enabled', '0') === '1') {
            global $wpdb;
            $table = $wpdb->prefix . 'mementor_tts_speeches';
            $row = $wpdb->get_var($wpdb->prepare(
                "SELECT 1 FROM {$table} WHERE post_id = %d AND (s3_url <> '' OR file_url <> '') LIMIT 1",
                $post_id
            ));
            if ($row) {
                return true;
            }
        }

        $upload_dir = wp_upload_dir();
        if (!empty($upload_dir['basedir'])) {
            $audio_dir  = trailingslashit($upload_dir['basedir']) . 'text-to-speech-tts/';
            $candidates = array(
                'mementor-' . $post_id . '-' . $language_code . '.mp3',
                'post-' . $post_id . '-' . $language_code . '.mp3',
                'post-' . $post_id . '.mp3',
            );
            foreach ($candidates as $filename) {
                if (file_exists($audio_dir . $filename)) {
                    return true;
                }
            }

            // Free-plan + SaaS-routed downloads land in /uploads/tts/ as
            // tts-{post_id}-{timestamp}.mp3 (see Mementor_TTS_Api_Client::download_to_uploads).
            $saas_dir = trailingslashit($upload_dir['basedir']) . 'tts/';
            if (is_dir($saas_dir)) {
                $matches = glob($saas_dir . 'tts-' . (int) $post_id . '-*.mp3');
                if (!empty($matches)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Register and enqueue the JavaScript for the public-facing side of the site.
     *
     * @since    1.0.0
     */
    public function enqueue_scripts() {
        // Only proceed if we should load assets or we're processing a shortcode
        if (!$this->should_load_assets() && !doing_filter('shortcode_atts_mementor_tts')) {
            $this->log_debug('enqueue_scripts: Not loading assets - should_load_assets=' . ($this->should_load_assets() ? 'true' : 'false'));
            return;
        }

        // Get current post ID - more robust method
        $post_id = 0;
        
        // Try different methods to get post ID
        if (is_singular()) {
            global $post;
            if ($post && isset($post->ID)) {
                $post_id = $post->ID;
            } else {
                // Fallback to queried object
                $queried_object = get_queried_object();
                if ($queried_object && isset($queried_object->ID)) {
                    $post_id = $queried_object->ID;
                }
            }
        }
        
        // Final fallback
        if (!$post_id) {
            $post_id = get_the_ID();
        }
        
        // Debug log enqueue attempt
        $this->log_debug('Attempting to enqueue scripts for post ID: ' . $post_id . ' (is_singular: ' . (is_singular() ? 'yes' : 'no') . ')');
        
        // Validate post ID before proceeding
        if (!$post_id || $post_id < 1) {
            $this->log_debug('Invalid post ID detected: ' . var_export($post_id, true) . ' - skipping script enqueue');
            return;
        }
        
        // Get audio URL
        $audio_url = $this->get_audio_url($post_id);
        
        // Generate audio if needed and if auto-generation is allowed (PRO feature)
        if (!$audio_url) {
            // Check if this is a PRO version or if auto-generation is enabled
            $is_pro = ttswp_has_paid_plan();
            $auto_generation_enabled = apply_filters('mementor_tts_auto_generation_enabled', false);
            
            // Only generate audio automatically if this is a PRO feature
            if ($is_pro && $auto_generation_enabled) {
                $this->generate_audio_for_post($post_id);
                $audio_url = $this->get_audio_url($post_id);
            }
        }

        // Only proceed if we have an audio URL
        if (!$audio_url) {
            $this->log_debug('No audio URL found for post ' . $post_id . ' - skipping script enqueue');
            return;
        }
        
        $this->log_debug('Audio URL found for post ' . $post_id . ': ' . $audio_url);

        // Enqueue the player script - jQuery will be automatically included as a dependency
        wp_enqueue_script('mementor-tts-player');
        
        // Localize script with necessary data
        wp_localize_script('mementor-tts-player', 'mementorTTSData', array(
            'labelText' => sanitize_text_field(get_option('mementor_tts_player_label', __('Listen to this article:', 'text-to-speech-tts'))),
            'showLabel' => (get_option('mementor_tts_show_player_label', '1') === '1' || get_option('mementor_tts_show_player_label', '1') === 1 || get_option('mementor_tts_show_player_label', '1') === true),
            'labelPosition' => sanitize_text_field(get_option('mementor_tts_player_label_position', 'left')),
            'labelColor' => sanitize_hex_color(get_option('mementor_tts_player_label_color', '#1d2327')),
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('mementor_tts_nonce'),
            'audioUrl' => $audio_url ? esc_url($audio_url) : '', // Handle empty audio URL gracefully
            'postId' => absint($post_id),
            'dashicons_url' => includes_url('css/dashicons.min.css'),
            'site_url' => site_url(),
            'version' => $this->version,
            'isDebug' => (get_option('mementor_tts_debug_mode', '0') === '1'),
            'hasAudio' => !empty($audio_url) // Flag to indicate if audio is available
        ));
        
        // Also localize with mementorTTS for compatibility
        wp_localize_script('mementor-tts-player', 'mementorTTS', array(
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('mementor_tts_nonce'),
            'postId' => absint($post_id),
            'debug' => (get_option('mementor_tts_debug_mode', '0') === '1'),
            'dashicons_url' => includes_url('css/dashicons.min.css'),
            'i18n' => array(
                'error' => __('Error:', 'text-to-speech-tts'),
                'generating' => __('Generating audio...', 'text-to-speech-tts'),
            )
        ));
        
        // Only load statistics tracking if enabled
        if (get_option('mementor_tts_enable_statistics', 'no') === 'yes') {
            wp_enqueue_script('mementor-tts-statistics');
            
            // Add statistics-specific data - merge with existing mementorTTS data
            wp_localize_script('mementor-tts-statistics', 'mementorTTSStats', array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'playerStatsNonce' => wp_create_nonce('mementor_tts_player_stats'),
                'postId' => absint($post_id),
                'statisticsEnabled' => true
            ));
        }

        // Sticky footer player — only for PRO users with sticky_footer placement
        if ( get_option('mementor_tts_player_position', 'after_content') === 'sticky_footer' && ttswp_has_paid_plan() ) {
            wp_enqueue_script(
                'mementor-tts-sticky-footer',
                MEMENTOR_TTS_PLUGIN_URL . 'public/js/mementor-tts-sticky-footer.js',
                array(),
                $this->version,
                true
            );
        }

        // Waveform progress bar — only for PRO users with waveform type
        if ( get_option('mementor_tts_progress_type', 'linear') === 'waveform_progress' && ttswp_has_paid_plan() ) {
            wp_enqueue_script(
                'mementor-tts-waveform',
                MEMENTOR_TTS_PLUGIN_URL . 'public/js/mementor-tts-waveform.js',
                array(),
                $this->version,
                true
            );
        }

        // Get the player HTML - generate even if no audio URL exists
        // This ensures the player structure is available for potential audio generation
        $player_html = $this->render_player($audio_url, $post_id);

        // Enqueue the player position and insert scripts (with player script as dependency)
        wp_enqueue_script('mementor-tts-player-position');
        wp_enqueue_script('mementor-tts-player-insert');
        
        // Also localize position to the position script
        wp_localize_script('mementor-tts-player-position', 'mementorTTSPlayerPosition', array(
            'position' => sanitize_text_field(get_option('mementor_tts_player_position', 'after_title'))
        ));
        
        // No special scripts needed for different page builders
        
        // Localize player insertion data
        wp_localize_script('mementor-tts-player-insert', 'mementorTTSPlayerHTML', array(
            'html' => $player_html,
            'hasAudio' => !empty($audio_url)
        ));
        
        wp_localize_script('mementor-tts-player-insert', 'mementorTTSPlayerPosition', array(
            'position' => sanitize_text_field(get_option('mementor_tts_player_position', 'after_title'))
        ));

        // Add alignment data for the player insert script
        wp_localize_script('mementor-tts-player-insert', 'mementorTTSPlayerAlignment', array(
            'alignment' => sanitize_text_field(get_option('mementor_tts_player_alignment', 'left'))
        ));

        // Add width data for the player insert script
        wp_localize_script('mementor-tts-player-insert', 'mementorTTSPlayerWidth', array(
            'width' => sanitize_text_field(get_option('mementor_tts_player_width', 'content_width')),
            'maxWidth' => absint(get_option('mementor_tts_player_max_width', 100)),
            'maxWidthUnit' => sanitize_text_field(get_option('mementor_tts_player_max_width_unit', '%'))
        ));

        // Add label data for the player insert script
        $show_label = get_option('mementor_tts_show_player_label', '1');
        wp_localize_script('mementor-tts-player-insert', 'mementorTTSPlayerLabel', array(
            'show_label' => ($show_label === '1' || $show_label === 1 || $show_label === true),
            'text' => sanitize_text_field(get_option('mementor_tts_player_label', __('Listen to this article:', 'text-to-speech-tts'))),
            'text_align' => sanitize_text_field(get_option('mementor_tts_player_label_position', 'left')),
            'font_size' => absint(get_option('mementor_tts_player_label_size', '14')),
            'font_weight' => absint(get_option('mementor_tts_player_label_weight', '400')),
            'color' => sanitize_hex_color(get_option('mementor_tts_player_label_color', '#1d2327'))
        ));
    }

    /**
     * Render the audio player inner HTML with container
     */
    public function render_player($audio_url, $content_id) {
        // Get player settings
        $player_alignment = get_option('mementor_tts_player_alignment', 'left');
        $player_width = get_option('mementor_tts_player_width', 'content_width');
        $label_position = get_option('mementor_tts_player_label_position', 'left');
        $show_time = get_option('mementor_tts_show_time', true);
        $show_volume = get_option('mementor_tts_show_volume', true);
        $speed_control = get_option('mementor_tts_speed_control', false);
        $show_download = get_option('mementor_tts_show_download', false);
        $show_info = get_option('mementor_tts_show_info', false);
        $show_play_bg = get_option('mementor_tts_show_play_bg', true);
        $show_label = get_option('mementor_tts_show_player_label', '1');
        $label_text = get_option('mementor_tts_player_label', __('Listen to this article:', 'text-to-speech-tts'));
        
        // Debug log player settings
        $this->log_debug('Rendering player with settings: show_label=' . wp_json_encode($show_label) . 
                        ', label_text="' . $label_text . '", speed_control=' . wp_json_encode($speed_control) . 
                        ', show_volume=' . wp_json_encode($show_volume) . 
                        ', show_download=' . wp_json_encode($show_download) .
                        ', player_alignment="' . $player_alignment . '", player_width="' . $player_width . '"');
        
        // Get container classes with explicit alignment class
        $container_classes = array(
            'mementor-tts-player-container',
            'mementor-tts-align-' . $player_alignment,
            'mementor-tts-width-' . $player_width
        );
        
        // Get max width value for custom class
        $max_width = absint(get_option('mementor_tts_player_max_width', 100));
        $max_width_unit = get_option('mementor_tts_player_max_width_unit', '%');
        
        // Only add max-width custom class if we're not using full_width
        if ($max_width > 0 && $player_width !== 'full_width') {
            $container_classes[] = 'mementor-tts-max-width-custom';
        }
        
        // Extract post ID from content_id (handle formats like 'post-123', 'shortcode-123', or just '123')
        $post_id = $content_id;
        if (strpos($content_id, '-') !== false) {
            $parts = explode('-', $content_id);
            $post_id = end($parts);
        }
        
        // Start the container with data attributes but no inline styles
        $player_html = '<div class="' . esc_attr(implode(' ', $container_classes)) . '" ' . 
                      'data-alignment="' . esc_attr($player_alignment) . '" ' . 
                      'data-max-width="' . esc_attr($max_width) . '" ' . 
                      'data-max-width-unit="' . esc_attr($max_width_unit) . '" ' .
                      'data-post-id="' . esc_attr($post_id) . '">';
        
        // Add label if enabled
        if ($show_label === '1' || $show_label === 1 || $show_label === true) {
            $label_color = sanitize_hex_color(get_option('mementor_tts_player_label_color', '#1d2327'));
            $label_size = absint(get_option('mementor_tts_player_label_size', '14'));
            $label_weight = absint(get_option('mementor_tts_player_label_weight', '400'));
            
            // Create CSS classes for the label instead of inline styles
            $label_classes = array(
                'mementor-tts-player-label',
                'text-' . esc_attr($label_position),
                'label-size-' . ($label_size <= 12 ? 'small' : ($label_size >= 16 ? 'large' : 'default')),
                'label-weight-' . ($label_weight >= 700 ? 'bold' : ($label_weight >= 500 ? 'medium' : 'normal')),
            );
            
            // Use data attribute for custom color instead of inline style
            $is_default_color = ($label_color === '#1d2327' || $label_color === '#000000' || empty($label_color));
            
            if ($is_default_color) {
                $label_classes[] = 'label-color-dark';
                $player_html .= '<div class="' . esc_attr(implode(' ', $label_classes)) . '">' . esc_html($label_text) . '</div>';
            } else {
                $label_classes[] = 'label-color-custom';
                $player_html .= '<div class="' . esc_attr(implode(' ', $label_classes)) . '" data-custom-color="' . esc_attr($label_color) . '">' . esc_html($label_text) . '</div>';
            }
        }
        
        // Add player element
        $player_html .= '<div class="mementor-tts-player">';
        
        // Only add audio source if we have a valid URL
        if (!empty($audio_url)) {
            $player_html .= '<audio preload="metadata"><source src="' . esc_url($audio_url) . '" type="audio/mpeg">' . esc_html__('Your browser does not support the audio element.', 'text-to-speech-tts') . '</audio>';
        } else {
            // Create audio element without source for potential dynamic loading
            $player_html .= '<audio preload="none">' . esc_html__('Your browser does not support the audio element.', 'text-to-speech-tts') . '</audio>';
        }
        
        // Add controls
        $player_html .= '<div class="mementor-tts-custom-controls"' . ($show_play_bg ? '' : ' data-show-play-bg="false"') . '>';
        
        // Add play button
        $play_button_classes = array('mementor-tts-play-button');
        if (!$show_play_bg) {
            $play_button_classes[] = 'no-background';
        }
        $player_html .= '<button class="' . esc_attr(implode(' ', $play_button_classes)) . '" style="padding:0!important;margin:0!important;"><span class="dashicons dashicons-controls-play mementor-dashicons mementor-dashicons-controls-play"></span></button>';
        
        if ($show_time) {
            $player_html .= '<span class="mementor-tts-time-display">0:00</span>';
        }
        
        $progress_type = get_option('mementor_tts_progress_type', 'linear');
        if ( $progress_type === 'waveform_progress' && ttswp_has_paid_plan() ) {
            $player_html .= '<div class="mementor-tts-progress-container mementor-tts-waveform" data-progress-type="waveform_progress" data-post-id="' . esc_attr($post_id) . '"></div>';
        } else {
            $player_html .= '<div class="mementor-tts-progress-container"><div class="mementor-tts-progress-bar"></div></div>';
        }

        if ($show_time) {
            $player_html .= '<span class="mementor-tts-duration-display">0:00</span>';
        }

        if ($show_volume) {
            $player_html .= '<button class="mementor-tts-volume-button" style="padding:0!important;margin:0!important;"><span class="dashicons dashicons-controls-volumeon mementor-dashicons mementor-dashicons-controls-volumeon"></span></button>';
        }
        
        if ($speed_control) {
            $player_html .= '<button class="mementor-tts-speed-button" style="padding:0!important;margin:0!important;">1x</button>';
        }
        
        if ($show_download) {
            $player_html .= '<a href="' . esc_url($audio_url) . '" download class="mementor-tts-download-button"><span class="dashicons dashicons-download mementor-dashicons mementor-dashicons-download"></span></a>';
        }
        
        if ($show_info) {
            $player_html .= '<button class="mementor-tts-info-button" style="padding:0!important;margin:0!important;"><span class="dashicons dashicons-info mementor-dashicons mementor-dashicons-info"></span></button>';
        }
        
        // Close the controls div
        $player_html .= '</div>';
        
        // Add the info popup outside the controls div but still inside the player div
        if ($show_info) {
            $player_html .= '<div class="mementor-tts-info-popup">';
            $player_html .= '<button type="button" class="mementor-tts-info-close" aria-label="' . esc_attr__('Close', 'text-to-speech-tts') . '" style="padding:0!important;margin:0!important;">&times;</button>';
            $player_html .= '<p>' . mementor_tts_info_popup_html() . '</p>';
            $player_html .= '</div>';
        }
        
        // Close the player div
        $player_html .= '</div>';
        
        // Close the container
        $player_html .= '</div>';
        
        return $player_html;
    }

    /**
     * Get container classes for the player
     */
    private function get_player_container_classes($additional_classes = array()) {
        // Get alignment setting
        $player_alignment = get_option('mementor_tts_player_alignment', 'left');
        
        // Build container classes
        $container_classes = array(
            'mementor-tts-player-container',
            'mementor-tts-align-' . sanitize_html_class($player_alignment)
        );
        
        // Add any additional classes
        if (!empty($additional_classes)) {
            $container_classes = array_merge($container_classes, (array)$additional_classes);
        }
        
        return $container_classes;
    }

    /**
     * Add player directly to Elementor content
     */
    public function add_player_to_elementor_content($content) {
        // Only add player on singular posts/pages
        if (!is_singular()) {
            return $content;
        }
        
        // Check if this post type is enabled
        $post_id = get_the_ID();
        $enabled_post_types = get_option('mementor_tts_post_types', array('post'));
        if (!in_array(get_post_type($post_id), $enabled_post_types)) {
            return $content;
        }
        
        // Get player position
        $position = get_option('mementor_tts_player_position', 'after_title');
        
        // Only proceed if we're using a position that requires content modification
        // For 'before_title' and 'after_title', we use different hooks
        if ($position !== 'after_content') {
            return $content;
        }
        
        // Get audio URL
        $audio_url = $this->get_audio_url($post_id);
        if (!$audio_url) {
            // Check if this is a PRO version or if auto-generation is enabled
            $is_pro = ttswp_has_paid_plan();
            $auto_generation_enabled = apply_filters('mementor_tts_auto_generation_enabled', false);

            // Only generate audio automatically if this is a PRO feature
            if ($is_pro && $auto_generation_enabled) {
                $this->generate_audio_for_post($post_id);
                $audio_url = $this->get_audio_url($post_id);
            }
            if (!$audio_url) {
                return $content;
            }
        }

        // Render player
        $player_html = '<div class="mementor-tts-player-container">';
        $player_html .= $this->render_player($audio_url, 'post-' . $post_id);
        $player_html .= '</div>';

        // Add player after content
        return $content . $player_html;
    }

    /**
     * Inject player after title using fallback method
     */
    public function inject_player_after_title_fallback($content) {
        // Only proceed if we haven't added the automatic player yet
        if ($this->automatic_player_added) {
            $this->log_debug('Automatic player already added, skipping fallback injection');
            return $content;
        }

        // Only add player on singular posts/pages in main query
        if (!is_singular() || !in_the_loop() || !is_main_query()) {
            $this->log_debug('Not a singular post or not in main query, skipping fallback injection');
            return $content;
        }

        // Get post ID and check if enabled
        $post_id = get_the_ID();
        $enabled_post_types = get_option('mementor_tts_post_types', array('post'));
        if (!in_array(get_post_type($post_id), $enabled_post_types)) {
            $this->log_debug('Post type not enabled, skipping fallback injection');
            return $content;
        }

        // Get audio URL
        $audio_url = $this->get_audio_url($post_id);
        if (!$audio_url) {
            // Check if this is a PRO version or if auto-generation is enabled
            $is_pro = ttswp_has_paid_plan();
            $auto_generation_enabled = apply_filters('mementor_tts_auto_generation_enabled', false);
            
            // Only generate audio automatically if this is a PRO feature
            if ($is_pro && $auto_generation_enabled) {
                $this->generate_audio_for_post($post_id);
                $audio_url = $this->get_audio_url($post_id);
            }
            if (!$audio_url) {
                $this->log_debug('No audio URL available, skipping fallback injection');
                return $content;
            }
        }

        $this->log_debug('Injecting player via fallback method');
        
        // Mark automatic player as added
        $this->automatic_player_added = true;

        // Get player alignment
        $player_alignment = get_option('mementor_tts_player_alignment', 'left');

        // Build player HTML with specific class for this position
        $container_classes = array(
            'mementor-tts-player-container',
            'mementor-tts-automatic',
            'mementor-tts-fallback',
            'mementor-tts-width-full',
            'constrained-width'
        );

        $player_html = '<div class="' . esc_attr(implode(' ', $container_classes)) . '" data-alignment="' . esc_attr($player_alignment) . '" data-post-id="' . esc_attr($post_id) . '" data-player-type="auto-inserted">';
        $player_html .= $this->render_player($audio_url, $post_id);
        $player_html .= '</div>';

        // Find the first paragraph or heading
        $pattern = '/(<h[1-6][^>]*>.*?<\/h[1-6]>|<p[^>]*>)/is';
        if (preg_match($pattern, $content, $matches, PREG_OFFSET_CAPTURE)) {
            $pos = $matches[0][1];
            return substr($content, 0, $pos) . $player_html . substr($content, $pos);
        }

        // If no suitable position found, prepend to content
        return $player_html . $content;
    }

    /**
     * Log a debug message
     * 
     * @param string $message The message to log
     * @param string $level The log level (debug, info, warning, error)
     */
    private function log_debug($message, $level = 'debug') {
        // Check if debug mode is enabled
        $debug_mode = get_option('mementor_tts_debug_mode', '0') === '1';
        
        // Only log if debug mode is enabled or this is an error-level message
        if (!$debug_mode && $level !== 'error') {
            return;
        }

        // Only log to file if WP_DEBUG_LOG is enabled
        if (!defined('WP_DEBUG_LOG') || !WP_DEBUG_LOG) {
            return;
        }

        $plugin_name = 'Mementor TTS';
        $formatted_message = sprintf('[%s] [%s] %s', $plugin_name, strtoupper($level), $message);

        if (function_exists('wp_debug_log')) {
            wp_debug_log($formatted_message);
        }
    }

    /**
     * Localize script with player data
     */
    public function localize_player_script() {
        // Get player settings from options
        $player_settings = get_option('mementor_tts_player_settings', array());

        // Add translations
        $player_settings = array_merge($player_settings, array(
            'i18n' => array(
                'play' => __('Play audio', 'text-to-speech-tts'),
                'pause' => __('Pause audio', 'text-to-speech-tts'),
                'restart' => __('Restart audio', 'text-to-speech-tts'),
                'forward' => __('Forward 10 seconds', 'text-to-speech-tts'),
                'backward' => __('Backward 10 seconds', 'text-to-speech-tts'),
                'speed' => __('Playback speed', 'text-to-speech-tts'),
                'download' => __('Download audio', 'text-to-speech-tts'),
                'loading' => __('Loading audio...', 'text-to-speech-tts'),
                'error' => __('Error loading audio', 'text-to-speech-tts'),
                'speed_set' => __('Speed: {0}', 'text-to-speech-tts')
            ),
            'dashicons_url' => includes_url('css/dashicons.min.css'),
            'site_url' => site_url()
        ));

        // Localize the script with player data
        wp_localize_script(
            'mementor-tts-player',
            'mementorTTSPlayer',
            $player_settings
        );
    }

    /**
     * Add automatic player to content
     */
    public function add_automatic_player($content) {
        // Check if player already added
        if ($this->automatic_player_added) {
            return $content;
        }

        // Get post ID
        $post_id = get_the_ID();
        if (!$post_id) {
            return $content;
        }

        // Check if player should be added
        if (!$this->should_add_player($post_id)) {
            return $content;
        }

        // Get audio URL
        $audio_url = $this->get_audio_url($post_id);
        if (!$audio_url) {
            return $content;
        }

        // Get player HTML
        $player_html = $this->render_player($audio_url, $post_id);
        
        // Mark as added
        $this->automatic_player_added = true;

        // Add player based on position
        $position = get_option('mementor_tts_player_position', 'before');
        if ($position === 'before') {
            return $player_html . $content;
        } else {
            return $content . $player_html;
        }
    }

    /**
     * Clear the dynamic CSS cache when player settings are updated
     *
     * @since    1.0.0
     */
    public function clear_dynamic_css_cache() {
        delete_transient('mementor_tts_dynamic_css');
    }

    /**
     * Clear the dynamic CSS cache when player settings are updated
     *
     * @since    1.0.0
     * @param string $option    Name of the updated option
     * @param mixed  $old_value The old option value
     * @param mixed  $value     The new option value
     */
    public function maybe_clear_dynamic_css_cache($option, $old_value, $value) {
        // List of options that affect the dynamic CSS
        $css_related_options = array(
            'mementor_tts_player_label_margin',
            'mementor_tts_player_label_size',
            'mementor_tts_player_label_weight',
            'mementor_tts_player_label_color',
            'mementor_tts_player_bg_color',
            'mementor_tts_player_border_color',
            'mementor_tts_player_text_color',
            'mementor_tts_player_accent_color',
            'mementor_tts_play_button_bg',
            'mementor_tts_timer_color',
            'mementor_tts_progress_bar_default',
            'mementor_tts_progress_bar_playing',
            'mementor_tts_play_icon_size',
            'mementor_tts_font_size',
            'mementor_tts_player_padding',
            'mementor_tts_player_max_width',
            'mementor_tts_player_max_width_unit'
        );

        // If the updated option affects CSS, clear the cache
        if (in_array($option, $css_related_options)) {
            $this->clear_dynamic_css_cache();
        }
    }

    /**
     * Get supported post types
     * 
     * @return array List of supported post types
     */
    private function get_supported_post_types() {
        // Get post types from settings, default to post only
        $post_types_setting = get_option('mementor_tts_post_types', array('post'));
        
        // If setting is not an array, make it one
        if (!is_array($post_types_setting)) {
            $post_types_setting = array('post');
        }
        
        // Allow filtering of supported post types
        return apply_filters('mementor_tts_supported_post_types', $post_types_setting);
    }

    /**
     * Maybe add player to content
     * 
     * @param string $content Post content
     * @return string Modified content with player
     */
    public function maybe_add_player_to_content($content) {
        // Get current post
        $post_id = get_the_ID();
        if (!$post_id) {
            return $content;
        }
        
        // Check if current post should have a player
        if (!$this->should_post_have_player($post_id)) {
            return $content;
        }
        
        // Check if audio exists - but don't bail out immediately
        $audio_url = $this->get_audio_url($post_id);
        $this->log_debug('Audio URL for post ' . $post_id . ': ' . ($audio_url ?: 'NONE'));
        
        // Only proceed if we have an audio URL for this post
        if (empty($audio_url)) {
            $this->log_debug('No audio URL for post ' . $post_id . ', skipping automatic player addition.');
            return $content; 
        }

        // Get player HTML (now we know audio exists)
        $player_html = $this->get_player_html($post_id);
        if (empty($player_html)) {
            $this->log_debug('No player HTML generated for post ' . $post_id);
            return $content;
        }
        
        // Get player position
        $position = get_option('mementor_tts_player_position', 'before');
        
        // Add player according to position
        if ($position === 'before') {
            return $player_html . $content;
        } else {
            return $content . $player_html;
        }
    }

    /**
     * Check if a post should have a player
     * 
     * @param int $post_id Post ID
     * @return bool Whether post should have a player
     */
    private function should_post_have_player($post_id) {
        // First check if we're on a singular post/page - this prevents player from appearing on homepage, archives, etc.
        if (!is_singular()) {
            $this->log_debug('Not on singular post/page - skipping player for post ' . $post_id);
            return false;
        }
        
        // Also check if we're on the front page or home page - prevent player from appearing there
        if (is_front_page() || is_home()) {
            $this->log_debug('On front page or home page - skipping player for post ' . $post_id);
            return false;
        }
        
        // Check settings for automatic player
        $auto_add = get_option('mementor_tts_auto_add_player', '1') === '1';
        $this->log_debug('Auto add player setting: ' . ($auto_add ? 'ENABLED' : 'DISABLED'));
        if (!$auto_add) {
            $this->log_debug('Auto add player is disabled - skipping player for post ' . $post_id);
            return false;
        }
        
        // Check if this post has automatic player disabled
        $disabled_for_post = get_post_meta($post_id, '_mementor_tts_disable_player', true);
        $this->log_debug('Player disabled for post ' . $post_id . ': ' . ($disabled_for_post ? 'YES' : 'NO'));
        if ($disabled_for_post) {
            $this->log_debug('Player is disabled for specific post ' . $post_id);
            return false;
        }
        
        // CRITICAL: Check if audio file actually exists for this post
        $audio_url = $this->get_audio_url($post_id);
        if (empty($audio_url)) {
            $this->log_debug('No audio file found for post ' . $post_id . ' - skipping player');
            return false;
        }
        $this->log_debug('Audio file found for post ' . $post_id . ': ' . $audio_url);
        
        // Allow filtering
        $result = apply_filters('mementor_tts_should_post_have_player', true, $post_id);
        $this->log_debug('Final should_post_have_player result for post ' . $post_id . ': ' . ($result ? 'YES' : 'NO'));
        return $result;
    }

    /**
     * Get player HTML
     * 
     * @param int $post_id Post ID
     * @return string Player HTML
     */
    public function get_player_html($post_id, $position = '') {
        // Get post content
        $post = get_post($post_id);
        if (!$post) {
            return '';
        }
        
        // Generate unique ID for this player
        $player_id = 'mementor-tts-player-' . $post_id;
        
        // Get post content for TTS
        $content = $this->prepare_content_for_tts($post->post_content);
        if (empty($content)) {
            return '';
        }
        
        // Get player alignment and width classes
        $alignment = get_option('mementor_tts_player_alignment', 'left');
        $width = get_option('mementor_tts_player_width', 'content_width');
        $alignment_class = 'mementor-tts-align-' . sanitize_html_class($alignment);
        $width_class = 'mementor-tts-width-' . sanitize_html_class($width);
        
        // Get show play background setting
        $show_play_bg = get_option('mementor_tts_show_play_bg', true);
        
        // Get the audio URL - use our detection method instead of meta
        $audio_url = $this->get_audio_url($post_id);

        // If no audio exists, don't render the player
        if (empty($audio_url)) {
            return '';
        }

        $status = 'ready';

        // Build HTML with position class
        $position_class = '';
        if ($position) {
            $position_class = 'mementor-tts-' . str_replace('_', '-', $position);
        }
        // Add inline style for max-width if needed
        $inline_style = '';
        $max_width = get_option('mementor_tts_player_max_width', '100');
        $max_width_unit = get_option('mementor_tts_player_max_width_unit', '%');
        if ($max_width != '100' || $max_width_unit != '%') {
            $inline_style = ' style="--mementor-tts-max-width: ' . esc_attr($max_width . $max_width_unit) . ';"';
        }
        
        $html = '<div class="mementor-tts-player-container ' . esc_attr($alignment_class) . ' ' . esc_attr($width_class) . ' ' . esc_attr($position_class) . '" data-player-type="auto-inserted"' . $inline_style . '>';
        
        // Add label if enabled - standardized check for consistency
        $show_label = get_option('mementor_tts_show_player_label', '1');
        $label_text = ''; // Initialize to prevent undefined variable warning
        if ($show_label === '1' || $show_label === 1 || $show_label === true) {
            $label_text = get_option('mementor_tts_player_label', __('Listen to this article:', 'text-to-speech-tts'));
            
            // Get label styling options
            $label_position = get_option('mementor_tts_player_label_position', 'left');
            $label_color = sanitize_hex_color(get_option('mementor_tts_player_label_color', '#1d2327'));
            $label_size = absint(get_option('mementor_tts_player_label_size', '14'));
            $label_weight = absint(get_option('mementor_tts_player_label_weight', '400'));
            
            // Create CSS classes for the label
            $label_classes = array(
                'mementor-tts-player-label',
                'text-' . esc_attr($label_position),
                'label-size-' . ($label_size <= 12 ? 'small' : ($label_size >= 16 ? 'large' : 'default')),
                'label-weight-' . ($label_weight >= 700 ? 'bold' : ($label_weight >= 500 ? 'medium' : 'normal')),
            );
            
            // Handle color styling
            $is_default_color = ($label_color === '#1d2327' || $label_color === '#000000' || empty($label_color));
            
            if ($is_default_color) {
                $label_classes[] = 'label-color-dark';
                $html .= '<div class="' . esc_attr(implode(' ', $label_classes)) . '">' . esc_html($label_text) . '</div>';
            } else {
                $label_classes[] = 'label-color-custom';
                // Use inline style for custom colors
                $html .= '<div class="' . esc_attr(implode(' ', $label_classes)) . '" style="color: ' . esc_attr($label_color) . ';">' . esc_html($label_text) . '</div>';
            }
        }
        // Debug log player settings for troubleshooting
        $this->log_debug('Player label settings in get_player_html: show_label=' . wp_json_encode($show_label) . ', label_text="' . $label_text . '"');
        
        // Add player with data attributes
        $html .= '<div id="' . esc_attr($player_id) . '" class="mementor-tts-player" ';
        $html .= 'data-post-id="' . esc_attr($post_id) . '" ';
        $html .= 'data-status="' . esc_attr($status) . '"';
        
        // Add audio URL if available
        if (!empty($audio_url)) {
            $html .= ' data-audio-url="' . esc_url($audio_url) . '"';
        }
        
        // Add autoplay data attribute
        if (get_option('mementor_tts_autoplay', false)) {
            $html .= ' data-autoplay="true"';
        }
        
        $html .= '>';
        
        // Player controls
        $html .= '<div class="mementor-tts-custom-controls"' . ($show_play_bg ? '' : ' data-show-play-bg="false"') . '>';
        
        // Play button
        $play_button_classes = array('mementor-tts-play-button');
        if (!$show_play_bg) {
            $play_button_classes[] = 'no-background';
        }
        $html .= '<button class="' . esc_attr(implode(' ', $play_button_classes)) . '" aria-label="' . esc_attr__('Play', 'text-to-speech-tts') . '" style="padding:0!important;margin:0!important;">';
        $html .= '<span class="dashicons dashicons-controls-play mementor-dashicons mementor-dashicons-controls-play"></span>';
        $html .= '</button>';
        
        // Build all controls in one line to prevent wpautop issues
        $controls = '';
        
        // Time display
        if (get_option('mementor_tts_show_time', true)) {
            $controls .= '<span class="mementor-tts-time-display">0:00</span>';
        }
        
        // Progress bar
        $progress_type = get_option('mementor_tts_progress_type', 'linear');
        if ( $progress_type === 'waveform_progress' && ttswp_has_paid_plan() ) {
            $controls .= '<div class="mementor-tts-progress-container mementor-tts-waveform" data-progress-type="waveform_progress" data-post-id="' . esc_attr($post_id) . '"></div>';
        } else {
            $controls .= '<div class="mementor-tts-progress-container"><div class="mementor-tts-progress-bar"></div></div>';
        }
        
        // Duration display
        if (get_option('mementor_tts_show_time', true)) {
            $controls .= '<span class="mementor-tts-duration-display">0:00</span>';
        }
        
        // Volume button
        if (get_option('mementor_tts_show_volume', true)) {
            $controls .= '<button class="mementor-tts-volume-button" aria-label="' . esc_attr__('Volume', 'text-to-speech-tts') . '" style="padding:0!important;margin:0!important;"><span class="dashicons dashicons-controls-volumeon mementor-dashicons mementor-dashicons-controls-volumeon"></span></button>';
        }
        
        // Speed control
        if (get_option('mementor_tts_speed_control', false)) {
            $controls .= '<button class="mementor-tts-speed-button" style="padding:0!important;margin:0!important;">1.0x</button>';
        }
        
        // Download button
        if (get_option('mementor_tts_show_download', false)) {
            if (!empty($audio_url)) {
                $controls .= '<a href="' . esc_url($audio_url) . '" download class="mementor-tts-download-button" aria-label="' . esc_attr__('Download', 'text-to-speech-tts') . '"><span class="dashicons dashicons-download mementor-dashicons mementor-dashicons-download"></span></a>';
            }
        }
        
        // Info button
        if (get_option('mementor_tts_show_info', false)) {
            $controls .= '<button type="button" class="mementor-tts-info-button" aria-label="' . esc_attr__('Information', 'text-to-speech-tts') . '" style="padding:0!important;margin:0!important;"><span class="dashicons dashicons-info mementor-dashicons mementor-dashicons-info"></span></button>';
        }
        
        $html .= $controls . '</div>'; // End controls
        
        // Add info popup if info button is enabled
        if (get_option('mementor_tts_show_info', false)) {
            $html .= '<div class="mementor-tts-info-popup" style="display: none;">';
            $html .= '<button type="button" class="mementor-tts-info-close" aria-label="' . esc_attr__('Close', 'text-to-speech-tts') . '" style="padding:0!important;margin:0!important;">&times;</button>';
            $html .= '<p>' . mementor_tts_info_popup_html() . '</p>';
            $html .= '</div>';
        }
        
        // Add audio element - all in one line
        $autoplay = get_option('mementor_tts_autoplay', false) ? ' autoplay' : '';
        if (!empty($audio_url)) {
            $html .= '<audio preload="metadata"' . $autoplay . '><source src="' . esc_url($audio_url) . '" type="audio/mpeg">' . esc_html__('Your browser does not support the audio element.', 'text-to-speech-tts') . '</audio>';
        } else {
            $html .= '<audio preload="none">' . esc_html__('Your browser does not support the audio element.', 'text-to-speech-tts') . '</audio>';
        }
        
        $html .= '</div></div>'; // End player and container
        
        return $html;
    }

    /**
     * Prepare content for TTS
     * 
     * @param string $content Post content
     * @return string Cleaned content for TTS
     */
    private function prepare_content_for_tts($content) {
        // Remove shortcodes
        $content = strip_shortcodes($content);
        
        // Strip HTML
        $content = wp_strip_all_tags($content);
        
        // Convert entities to text
        $content = html_entity_decode($content, ENT_QUOTES, 'UTF-8');
        
        // Clean up whitespace
        $content = preg_replace('/\s+/', ' ', $content);
        $content = trim($content);
        
        // Allow filtering
        return apply_filters('mementor_tts_prepare_content', $content);
    }
    
    /**
     * Recursively extract text content from Elementor data structure.
     *
     * When post_content contains raw Elementor JSON instead of rendered HTML,
     * this method parses the _elementor_data to extract actual text content.
     *
     * @since 1.9.4
     * @param array $data Decoded Elementor data array.
     * @return string HTML content extracted from the data.
     */
    private function extract_text_from_elementor_data($data) {
        $html = '';

        foreach ($data as $element) {
            if (!is_array($element)) {
                continue;
            }

            // Check for CSS classes that should be excluded (e.g., no-audio)
            $css_classes = '';
            if (isset($element['settings']['css_classes'])) {
                $css_classes = $element['settings']['css_classes'];
            }
            if (isset($element['settings']['_css_classes'])) {
                $css_classes .= ' ' . $element['settings']['_css_classes'];
            }

            if (strpos($css_classes, 'no-audio') !== false) {
                continue;
            }

            // Extract text from known content fields
            if (isset($element['settings']) && is_array($element['settings'])) {
                $text_fields = array('editor', 'title', 'description', 'text', 'content');
                foreach ($text_fields as $field) {
                    if (!empty($element['settings'][$field]) && is_string($element['settings'][$field])) {
                        $stripped = trim(wp_strip_all_tags($element['settings'][$field]));
                        if (!empty($stripped)) {
                            $html .= $element['settings'][$field];
                        }
                    }
                }
            }

            // Recurse into nested elements
            if (!empty($element['elements']) && is_array($element['elements'])) {
                $html .= $this->extract_text_from_elementor_data($element['elements']);
            }
        }

        return $html;
    }

    /**
     * Output AudioObject schema markup for SEO
     * 
     * @since 1.6.9
     */
    public function output_audio_schema() {
        // Prevent duplicate output when multiple Public instances exist
        static $already_output = false;
        if ($already_output) {
            return;
        }

        // Only output on singular posts/pages
        if (!is_singular()) {
            return;
        }
        
        // Check if schema is enabled (PRO feature)
        $is_enabled = get_option('mementor_tts_enable_schema', 'no') === 'yes';
        if (!$is_enabled) {
            return;
        }
        
        // Check if user has a paid plan
        if (!ttswp_has_paid_plan()) {
            return;
        }
        
        global $post;
        if (!$post) {
            return;
        }
        
        // Check if post has audio
        global $wpdb;
        $table_name = $wpdb->prefix . 'mementor_tts_speeches';
        
        $speech = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$table_name} WHERE post_id = %d ORDER BY created_at DESC LIMIT 1",
            $post->ID
        ));
        
        // If no database record, check post meta as fallback
        $audio_url = '';
        $duration = '';
        $language = get_locale();
        
        if ($speech) {
            // Get from database - prefer S3 URL if Media Offload is enabled
            $media_offload_enabled = get_option('mementor_tts_s3_enabled', '0') === '1';

            if ($media_offload_enabled && !empty($speech->s3_url)) {
                $audio_url = $speech->s3_url;
            } elseif (!empty($speech->file_url)) {
                $audio_url = $speech->file_url;
            } elseif (!empty($speech->audio_file)) {
                // Fall back to constructing URL from audio_file
                $upload_dir = wp_upload_dir();
                $audio_url = trailingslashit($upload_dir['baseurl']) . 'text-to-speech-tts/' . $speech->audio_file;
            }

            $duration = $speech->duration ?? '';
            $language = $speech->language ?? get_locale();
        } else {
            // Try post meta fallback
            $has_audio = get_post_meta($post->ID, '_mementor_tts_has_audio', true);
            $meta_audio_url = get_post_meta($post->ID, '_mementor_tts_audio_url', true);
            
            if ($has_audio && $meta_audio_url) {
                $audio_url = $meta_audio_url;
                
                // Try to estimate duration from file
                $upload_dir = wp_upload_dir();
                $audio_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $meta_audio_url);
                
                if (file_exists($audio_path)) {
                    // Try getID3 first if available
                    if (class_exists('getID3')) {
                        $getID3 = new getID3();
                        $file_info = $getID3->analyze($audio_path);
                        
                        if (isset($file_info['playtime_seconds'])) {
                            $duration = round($file_info['playtime_seconds']);
                        }
                    } else {
                        // Fallback: Estimate duration based on file size
                        // Average MP3 bitrate is ~128 kbps = 16 KB/s
                        $filesize = filesize($audio_path);
                        if ($filesize) {
                            // Rough estimate: file size in bytes / 16000 = duration in seconds
                            $duration = round($filesize / 16000);
                        }
                    }
                }
            }
        }
        
        if (empty($audio_url)) {
            return;
        }
        
        // Format duration in ISO 8601 format if we have it from database
        $duration_iso = '';
        if (!empty($duration)) {
            $seconds = intval($duration);
            $minutes = floor($seconds / 60);
            $remaining_seconds = $seconds % 60;
            
            $duration_iso = 'PT';
            if ($minutes > 0) {
                $duration_iso .= $minutes . 'M';
            }
            if ($remaining_seconds > 0) {
                $duration_iso .= $remaining_seconds . 'S';
            }
        }
        
        // Convert WordPress locale to BCP 47 format (e.g., en_US to en-US)
        $language = str_replace('_', '-', $language);
        
        // Build schema
        $schema = array(
            '@context' => 'https://schema.org',
            '@type' => 'AudioObject',
            'name' => get_the_title() . ' – ' . __('Audio Version', 'text-to-speech-tts'),
            'contentUrl' => esc_url($audio_url),
            'datePublished' => get_the_date('c'),
            'inLanguage' => $language,
            'encodingFormat' => 'audio/mpeg'
        );
        
        // Add duration if available
        if (!empty($duration_iso)) {
            $schema['duration'] = $duration_iso;
        }
        
        // Add author information
        $author_name = get_the_author();
        if (!empty($author_name)) {
            $schema['author'] = array(
                '@type' => 'Person',
                'name' => $author_name
            );
        }
        
        // Add description - use clean excerpt without player HTML
        $post_obj = get_post($post->ID);
        $description = '';
        
        // First try to get a clean excerpt
        if (!empty($post_obj->post_excerpt)) {
            $description = $post_obj->post_excerpt;
        } else {
            // Generate excerpt from content, but strip shortcodes and HTML
            $content = $post_obj->post_content;
            $content = strip_shortcodes($content);
            $content = wp_strip_all_tags($content);
            $description = wp_trim_words($content, 30);
        }
        
        if (!empty($description)) {
            $schema['description'] = $description;
        }
        
        // Add transcript (the original post content)
        $schema['transcript'] = get_permalink();
        
        // Allow filtering the schema
        $schema = apply_filters('mementor_tts_audio_schema', $schema, $post, $speech);
        
        // Output the schema
        echo "\n<!-- Text to Speech AudioObject Schema -->\n";
        echo '<script type="application/ld+json">' . "\n";
        echo wp_json_encode($schema, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        echo "\n</script>\n";
        echo "<!-- End Text to Speech AudioObject Schema -->\n\n";

        $already_output = true;
    }
}

if ( ! function_exists( 'mementor_tts_info_popup_html' ) ) {
    /**
     * Localized attribution text shown in the player's Information popup.
     *
     * Returns already-escaped HTML safe to echo directly. Three separate
     * links (Mementor agency, this plugin, ElevenLabs) — each URL, title,
     * and anchor text is translatable so .po/.mo files can swap Norwegian
     * URLs and phrasing (e.g. "ElevenLabs" → "teknologi fra ElevenLabs").
     */
    function mementor_tts_info_popup_html() {
        // Match the visitor's current language (e.g. Weglot serving Norwegian
        // while WP's own locale is still en_US). Without this swap, __() / _x()
        // would always return English even on the /no/ page.
        $switched_locale = false;
        $visitor_lang    = '';
        if ( function_exists( 'weglot_get_current_language' ) ) {
            $lang = weglot_get_current_language();
            if ( is_object( $lang ) && method_exists( $lang, 'getInternalCode' ) ) {
                $visitor_lang = $lang->getInternalCode();
            } elseif ( is_object( $lang ) ) {
                $visitor_lang = (string) $lang;
            } else {
                $visitor_lang = (string) $lang;
            }
        }
        $locale_map = array(
            'no' => 'nb_NO',
            'nb' => 'nb_NO',
            'nn' => 'nn_NO',
        );
        if ( isset( $locale_map[ $visitor_lang ] ) && $locale_map[ $visitor_lang ] !== get_locale() ) {
            $switched_locale = switch_to_locale( $locale_map[ $visitor_lang ] );
            if ( $switched_locale ) {
                // switch_to_locale fires 'change_locale' but registered text
                // domains don't auto-reload in the new locale — force this one.
                unload_textdomain( 'text-to-speech-tts' );
                $mofile = WP_LANG_DIR . '/plugins/text-to-speech-tts-' . $locale_map[ $visitor_lang ] . '.mo';
                if ( file_exists( $mofile ) ) {
                    load_textdomain( 'text-to-speech-tts', $mofile );
                }
            }
        }

        // Use _x() with a translation context so these anchor texts get their
        // own .po entries and don't collide with identical strings used
        // elsewhere (e.g. "ElevenLabs" appears in several unrelated places).
        $mementor_url   = __( 'https://mementor.no/en/', 'text-to-speech-tts' );
        $mementor_title = _x( 'Web Design & Digital Marketing Agency in Norway', 'Info popup link title', 'text-to-speech-tts' );
        $mementor_text  = _x( "Mementor's", 'Info popup link anchor', 'text-to-speech-tts' );

        $plugin_url  = __( 'https://ttswp.com/', 'text-to-speech-tts' );
        $plugin_text = _x( 'Text-to-Speech plugin', 'Info popup link anchor', 'text-to-speech-tts' );

        $el_url  = 'https://try.elevenlabs.io/ttswp';
        $el_text = _x( 'ElevenLabs', 'Info popup link anchor', 'text-to-speech-tts' );

        $mementor_anchor = '<a href="' . esc_url( $mementor_url ) . '" target="_blank" rel="noopener" title="' . esc_attr( $mementor_title ) . '">' . esc_html( $mementor_text ) . '</a>';
        $plugin_anchor   = '<a href="' . esc_url( $plugin_url )   . '" target="_blank" rel="noopener">' . esc_html( $plugin_text ) . '</a>';
        $el_anchor       = '<a href="' . esc_url( $el_url )       . '" target="_blank" rel="noopener">' . esc_html( $el_text ) . '</a>';

        $html = sprintf(
            /* translators: %1$s: Mementor agency link, %2$s: Text-to-Speech plugin link, %3$s: ElevenLabs link */
            __( 'Generated with %1$s %2$s for WordPress, using %3$s.', 'text-to-speech-tts' ),
            $mementor_anchor,
            $plugin_anchor,
            $el_anchor
        );

        if ( $switched_locale ) {
            restore_previous_locale();
            // Reload the default-locale textdomain so subsequent __() calls on
            // this request still translate correctly.
            unload_textdomain( 'text-to-speech-tts' );
            $default_mofile = WP_LANG_DIR . '/plugins/text-to-speech-tts-' . get_locale() . '.mo';
            if ( file_exists( $default_mofile ) ) {
                load_textdomain( 'text-to-speech-tts', $default_mofile );
            }
        }

        return $html;
    }
}

