<?php
// Prevent direct access to this file
if (!defined('ABSPATH')) {
    exit;
}

/**
 * The core plugin class
 */
class Mementor_Text_To_Speech {

    /**
     * The loader that's responsible for maintaining and registering all hooks that power
     * the plugin.
     */
    protected $loader;

    /**
     * The unique identifier of this plugin.
     */
    protected $plugin_name;

    /**
     * The current version of the plugin.
     */
    protected $version;

    /**
     * The text domain for this plugin.
     */
    protected $text_domain;

    /**
     * Initialize the class and set its properties.
     */
    public function __construct() {
        if ( defined( 'MEMENTOR_TTS_VERSION' ) ) {
            $this->version = MEMENTOR_TTS_VERSION;
        } else {
            $this->version = '1.0.0';
        }
        $this->plugin_name = 'text-to-speech-tts';
        $this->text_domain = 'text-to-speech-tts';

        // Include error handler early in case we need it during loading
        $this->load_error_handler();
        $this->load_dependencies();
        $this->set_locale();
        $this->define_admin_hooks();
        $this->define_public_hooks();
        $this->register_shortcodes();
        $this->register_blocks();
        
        // Initialize Elementor integration if Elementor is active
        add_action('plugins_loaded', array($this, 'init_elementor_integration'));

    }

    /**
     * Load the required dependencies for this plugin.
     */
    private function load_dependencies() {
        // Load the loader class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-loader.php';

        // Load the i18n class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-i18n.php';

        // Load the i18n helper class for multi-language support (Weglot, WPML, etc.)
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-i18n-helper.php';

        // Load the admin class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'admin/class-mementor-tts-admin.php';

        // Load the AJAX handler class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-ajax.php';

        // Load the public class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-public.php';

        // Load the shortcodes class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-shortcodes.php';

        // Load the speech builder class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-speech-builder.php';

        // Load the ElevenLabs API class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-elevenlabs-api.php';

        // Load the SaaS API client
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-api-client.php';

        // Load the special license key manager
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-special-license.php';
        
        // Load compatibility fixes
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/compatibility-fixes.php';
        
        // Load CSS compatibility handler
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-css-compatibility.php';
        
        // Load theme compatibility handler
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-theme-compatibility.php';
        
        // Load Fusion Builder compatibility
        if (file_exists(MEMENTOR_TTS_PLUGIN_DIR . 'includes/fusion-builder-compatibility.php')) {
            require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/fusion-builder-compatibility.php';
        }
        
        // Load Fusion Builder debug script if debug mode is enabled
        if (defined('MEMENTOR_TTS_DEBUG') && MEMENTOR_TTS_DEBUG) {
            if (file_exists(MEMENTOR_TTS_PLUGIN_DIR . 'debug-fusion-builder.php')) {
                require_once MEMENTOR_TTS_PLUGIN_DIR . 'debug-fusion-builder.php';
            }
        }
        
        // Load cache compatibility handler
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-cache-compatibility.php';
        
        // Load the player statistics class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-player-statistics.php';

        // Load the transcriptions class
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-transcriptions.php';

        // Load the admin dashboard widget (TTSWP changelog + blog news)
        require_once MEMENTOR_TTS_PLUGIN_DIR . 'includes/class-mementor-tts-dashboard-widget.php';

        // PRO bridge removed — plan gates now use ttswp_has_paid_plan() from SaaS connection

        // Initialize the loader
        $this->loader = new Mementor_TTS_Loader();
    }

    /**
     * Register all of the hooks related to the admin area functionality
     */
    private function define_admin_hooks() {
        $plugin_admin = new Mementor_TTS_Admin($this->get_plugin_name(), $this->get_version());

        $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
        $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
        $this->loader->add_action('admin_menu', $plugin_admin, 'add_plugin_admin_menu');

        // Initialize AJAX handler using singleton pattern
        $plugin_ajax = Mementor_TTS_Ajax::get_instance();

        // Initialize player statistics
        $player_stats = Mementor_TTS_Player_Statistics::get_instance();

        // Initialize transcriptions
        $transcriptions = Mementor_TTS_Transcriptions::get_instance();

        // Register the dashboard widget (TTSWP changelog + blog news)
        Mementor_TTS_Dashboard_Widget::get_instance()->register();

        // Register per-license credit limit filter
        add_filter('mementor_tts_pro_credit_limit', array($this, 'filter_pro_credit_limit'), 10, 2);

        // Check and create tables if needed for existing users
        $this->loader->add_action('admin_init', $this, 'maybe_create_statistics_tables');

        // Add localization
        $this->loader->add_action('admin_enqueue_scripts', $this, 'localize_scripts');

        // Sync existing audio to media library when the setting is turned ON
        add_action('update_option_mementor_tts_media_library', array($this, 'sync_existing_audio_to_media_library'), 10, 2);
        add_action('add_option_mementor_tts_media_library', array($this, 'on_add_media_library_option'), 10, 2);
    }

    /**
     * Sync existing audio to media library when setting is turned ON.
     * Fires on update_option_mementor_tts_media_library.
     *
     * @param string $old_value Previous option value.
     * @param string $new_value New option value.
     */
    public function sync_existing_audio_to_media_library($old_value, $new_value) {
        if ($new_value !== 'yes') {
            return;
        }

        $this->do_media_library_sync();
    }

    /**
     * Handle first-time save of media library option.
     * Fires on add_option_mementor_tts_media_library.
     *
     * @param string $option Option name.
     * @param string $value  Option value.
     */
    public function on_add_media_library_option($option, $value) {
        if ($value !== 'yes') {
            return;
        }

        $this->do_media_library_sync();
    }

    /**
     * Scan all posts with TTS audio and register them as media attachments.
     * Uses post meta (_mementor_tts_audio_url) as the source of truth.
     */
    private function do_media_library_sync() {
        global $wpdb;

        // Ensure the Processor class is loaded (may not be during options.php processing)
        if (!class_exists('Mementor_TTS_Processor')) {
            $processor_file = plugin_dir_path(__FILE__) . 'class-mementor-tts-processor.php';
            if (file_exists($processor_file)) {
                require_once $processor_file;
            } else {
                error_log('TTS Media Library Sync: Processor class file not found');
                return;
            }
        }

        // Find all posts that have TTS audio via post meta
        // Check both the base key (_mementor_tts_audio_url) and language-specific keys (_mementor_tts_audio_url_en, etc.)
        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT pm.post_id, pm.meta_value AS audio_url
                 FROM {$wpdb->postmeta} pm
                 INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
                 WHERE pm.meta_key LIKE %s
                 AND pm.meta_value != ''
                 AND p.post_status != 'trash'
                 GROUP BY pm.post_id",
                $wpdb->esc_like('_mementor_tts_audio_url') . '%'
            )
        );

        if (empty($results)) {
            error_log('TTS Media Library Sync: No posts with TTS audio found');
            return;
        }

        error_log('TTS Media Library Sync: Found ' . count($results) . ' posts with TTS audio');

        $upload_dir = wp_upload_dir();
        $processor = Mementor_TTS_Processor::get_instance();
        $synced = 0;

        foreach ($results as $row) {
            // Skip if already synced (also verify the attachment still exists)
            $existing_attachment_id = get_post_meta($row->post_id, '_mementor_tts_attachment_id', true);
            if ($existing_attachment_id && get_post($existing_attachment_id)) {
                continue;
            }
            // Clean up orphaned meta if attachment was manually deleted
            if ($existing_attachment_id && !get_post($existing_attachment_id)) {
                delete_post_meta($row->post_id, '_mementor_tts_attachment_id');
            }

            // Skip S3-hosted files (no local file to attach)
            if (strpos($row->audio_url, 'amazonaws.com') !== false || strpos($row->audio_url, '.s3.') !== false) {
                continue;
            }

            // Convert URL to file path
            $file_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $row->audio_url);

            // Skip if file doesn't exist on disk
            if (!file_exists($file_path)) {
                error_log('TTS Media Library Sync: File not found for post #' . $row->post_id . ': ' . $file_path);
                continue;
            }

            $result = $processor->add_to_media_library($file_path, $row->post_id);
            if ($result) {
                $synced++;
                error_log('TTS Media Library Sync: Created attachment for post #' . $row->post_id);
            }
        }

        // Also scan the audio directory for files not tracked in post meta (e.g., shortcode audio)
        $audio_dir = $upload_dir['basedir'] . '/text-to-speech-tts/';
        if (is_dir($audio_dir)) {
            $files = glob($audio_dir . '*.mp3');
            if ($files) {
                // Get all file paths already registered as attachments to avoid duplicates
                $existing_attachments = $wpdb->get_col(
                    $wpdb->prepare(
                        "SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = '_wp_attached_file' AND meta_value LIKE %s",
                        '%' . $wpdb->esc_like('text-to-speech-tts/') . '%'
                    )
                );
                // Normalize to just filenames for comparison
                $existing_filenames = array_map('basename', $existing_attachments);

                foreach ($files as $file) {
                    $filename = basename($file);
                    if (in_array($filename, $existing_filenames, true)) {
                        continue; // Already in media library
                    }

                    // Try to find the parent post_id from filename (format: mementor-{id}-{lang}.mp3)
                    $parent_post_id = 0;
                    if (preg_match('/^mementor-(\d+)-/', $filename, $matches)) {
                        $candidate_id = absint($matches[1]);
                        $candidate_post = get_post($candidate_id);
                        if ($candidate_post && $candidate_post->post_status !== 'trash') {
                            $parent_post_id = $candidate_id;
                        }
                    }

                    $result = $processor->add_to_media_library($file, $parent_post_id);
                    if ($result) {
                        $synced++;
                        error_log('TTS Media Library Sync: Created attachment for file ' . $filename . ($parent_post_id > 0 ? ' (post #' . $parent_post_id . ')' : ' (unattached)'));
                    }
                }
            }
        }

        error_log('TTS Media Library Sync: Synced ' . $synced . ' total audio files to Media Library');
    }

    /**
     * Register all of the hooks related to the public-facing functionality
     * of the plugin.
     *
     * @since    1.0.0
     * @access   private
     */
    private function define_public_hooks() {
        // Initialize public-facing functionality
        // !!! MAKE SURE THIS LINE IS ***NOT*** COMMENTED OUT !!!
        $plugin_public = new Mementor_TTS_Public($this->get_plugin_name(), $this->get_version());

        // Initialize shortcodes using singleton pattern
        $plugin_shortcodes = Mementor_TTS_Shortcodes::instance($this->get_plugin_name(), $this->get_version());

        // Add public hooks for styles and scripts
        // Priority 999 ensures our CSS loads AFTER theme CSS to override theme button styles
        $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_styles', 999);
        $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts', 999);

        // Setup content filters for player insertion - Hooked to template_redirect to run only on frontend
        $this->loader->add_action('template_redirect', $plugin_public, 'setup_content_filters'); // This hook is correct

        // Add shortcode initialization hook - this ensures WordPress is fully loaded
        $this->loader->add_action('init', $plugin_shortcodes, 'register_shortcodes');
        
        // Add filter to determine if assets should be loaded
        $this->loader->add_filter('mementor_tts_should_load_assets', $plugin_public, 'filter_should_load_assets', 10, 1);
    }

    /**
     * Run the plugin.
     */
    public function run() {
        $this->loader->run();
    }

    /**
     * Check and create player statistics tables if they don't exist
     *
     * This method is called on admin_init to ensure existing users
     * get the statistics tables created when they update the plugin
     *
     * @since    1.4.2
     */
    public function maybe_create_statistics_tables() {
        // Check if tables need to be created
        $db_version = get_option('mementor_tts_player_stats_db_version', '0');
        
        if (version_compare($db_version, '1.0', '<')) {
            // Tables don't exist yet, create them
            $player_stats = Mementor_TTS_Player_Statistics::get_instance();
            $player_stats->create_tables();
        }
    }

    /**
     * Filter the PRO credit limit for a specific license key.
     *
     * Allows per-license custom credit limits. License keys are matched
     * by SHA-256 hash so raw keys are not stored in source code.
     *
     * @param int    $default_limit The default credit limit (75000).
     * @param string $license_key   The PRO license key.
     * @return int The credit limit to use.
     */
    public function filter_pro_credit_limit($default_limit, $license_key) {
        if (empty($license_key)) {
            return $default_limit;
        }

        // SHA-256 hash → custom monthly character limit
        // To add a new license: hash the uppercase key with sha256 and add an entry.
        $custom_limits = array(
            '79cf304886442a30494fd8714420d89f52646c6f7e12bf2858452e085858b17b' => 275000,
            'd07159fffc21fe9da6a91c96b4c06879dbbe5e834c396a736c87fb03006b00bb' => 100000,
            '445d5dcf82d395e8d0d32aced72e8002e75f49f8d23b8d233205930ce2795eae' => 575000,
        );

        $key_hash = hash('sha256', strtoupper(trim($license_key)));

        return isset($custom_limits[$key_hash]) ? $custom_limits[$key_hash] : $default_limit;
    }

    /**
     * The name of the plugin used to uniquely identify it within the context of
     * WordPress and to define internationalization functionality.
     */
    public function get_plugin_name() {
        return $this->plugin_name;
    }

    /**
     * Retrieve the version number of the plugin.
     */
    public function get_version() {
        return $this->version;
    }

    /**
     * The reference to the class that orchestrates the hooks with the plugin.
     */
    public function get_loader() {
        return $this->loader;
    }

    /**
     * Localize scripts with necessary data
     */
    public function localize_scripts() {
        wp_localize_script('mementor-tts-admin', 'mementorTTS', array(
            'nonce' => wp_create_nonce('mementor_tts_nonce'),
            'ajaxurl' => admin_url('admin-ajax.php'),
            'pluginUrl' => MEMENTOR_TTS_PLUGIN_URL,
            'currentVoiceId' => get_option('mementor_tts_voice', ''),
            'compatibilityMode' => (get_option('mementor_tts_compatibility_mode', '0') === '1'),
            'isPro' => ttswp_has_paid_plan(),
            'strings' => array(
                'validating' => __('Validating...', 'text-to-speech-tts'),
                'connected' => __('Connected', 'text-to-speech-tts'),
                'notConnected' => __('Not Connected', 'text-to-speech-tts'),
                'confirmReset' => __('Are you sure you want to reset the API settings?', 'text-to-speech-tts'),
                'generating' => __('Generating audio...', 'text-to-speech-tts'),
                'error' => __('Error:', 'text-to-speech-tts'),
                'voicesLoaded' => __('Voices loaded successfully', 'text-to-speech-tts'),
                'loadingVoices' => __('Loading voices...', 'text-to-speech-tts'),
                'failedToLoadVoices' => __('Failed to load voices. Please try again.', 'text-to-speech-tts'),
                'errorLoadingVoices' => __('Error loading voices', 'text-to-speech-tts'),
                'noVoicesFound' => __('No voices found matching your filters.', 'text-to-speech-tts'),
                'savingVoice' => __('Saving voice selection...', 'text-to-speech-tts'),
                'failedToSaveVoice' => __('Failed to save voice selection.', 'text-to-speech-tts'),
                'errorSavingVoice' => __('Error saving voice selection', 'text-to-speech-tts')
            )
        ));
    }

    /**
     * Initialize Elementor integration
     *
     * @since    1.0.0
     * @access   public
     */
    public function init_elementor_integration() {
        // Check if Elementor is active
        if (!did_action('elementor/loaded')) {
            return;
        }

        // Add filter to load assets when Elementor is active
        add_filter('mementor_tts_should_load_assets', function($should_load) {
            // Safely get parameters using filter_input
            $elementor_preview_id = filter_input(INPUT_GET, 'elementor-preview', FILTER_VALIDATE_INT);
            $nonce = filter_input(INPUT_GET, '_wpnonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS);

            // Check capabilities and if parameters are valid
            if ($elementor_preview_id && $nonce && current_user_can('edit_posts')) {
                // Verify nonce - Use a dynamic action based on the preview ID
                if (wp_verify_nonce($nonce, 'elementor_editor-' . $elementor_preview_id)) {
                    return true; // Nonce verified, load assets
                }
            }
            
            // If nonce check fails or conditions not met, return original value
            return $should_load;
        });

        // Add hooks for Elementor compatibility
        add_action('elementor/frontend/after_enqueue_styles', function() {
            // Safely get parameters using filter_input
            $elementor_preview_id = filter_input(INPUT_GET, 'elementor-preview', FILTER_VALIDATE_INT);
            $nonce = filter_input(INPUT_GET, '_wpnonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS);

            // Check capabilities and if parameters are valid
            if ($elementor_preview_id && $nonce && current_user_can('edit_posts')) {
                // Verify nonce - Use a dynamic action based on the preview ID
                if (wp_verify_nonce($nonce, 'elementor_editor-' . $elementor_preview_id)) {
                    // Nonce verified, enqueue necessary styles and scripts
                    wp_enqueue_style('dashicons');
                    wp_enqueue_style('mementor-tts-shared');
                    wp_enqueue_script('mementor-tts-player');
                    wp_enqueue_script('mementor-tts-player-position');
                    wp_enqueue_script('mementor-tts-player-insert');
                }
            }
        });
    }

    /**
     * Load error handler for plugin
     *
     * @since    1.0.0
     * @access   private
     */
    private function load_error_handler() {
        // No custom error or exception handlers in production code
        // Let WordPress handle errors using its built-in mechanisms
    }

    /**
     * Define the locale for this plugin for internationalization.
     *
     * @since    1.0.0
     * @access   private
     */
    private function set_locale() {
        $plugin_i18n = new Mementor_TTS_i18n();
        // Re-add the hook to load text domain from the languages directory
        $this->loader->add_action('plugins_loaded', $plugin_i18n, 'load_plugin_textdomain');
    }

    /**
     * Register shortcodes
     * 
     * This method sets up the registration of plugin shortcodes
     * 
     * @since    1.0.0
     * @access   private
     */
    private function register_shortcodes() {
        // Shortcodes are registered via the Mementor_TTS_Shortcodes class
        // The actual registration occurs in define_public_hooks()
        // This method exists to ensure consistent initialization order
    }

    /**
     * Register blocks
     * 
     * This method sets up the registration of Gutenberg blocks.
     * It is designed to be resilient if block files are missing.
     * 
     * @since    1.0.0
     * @access   private
     */
    private function register_blocks() {
        // The actual block registration is handled in the main plugin file
        // This method exists primarily to ensure the registration hooks are in place
        // No additional code needed here as the main file already handles the registration
    }


    /**
     * Register the JavaScript for the public-facing side of the site.
     *
     * @since    1.0.0
     */
    public function enqueue_scripts() {
        wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . '../public/js/mementor-tts-public.js', array('jquery'), $this->version, true);
        
        // Add localized script data for AJAX requests
        wp_localize_script($this->plugin_name, 'mementorTTS', array(
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('mementor_tts_nonce'),
            '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'),
            )
        ));
    }
}
