<?php
/**
 * Plugin Name: AI Content Generator & Calculator Builder by TalkGenAI – GEO, SEO & Widgets
 * Plugin URI: https://app.talkgen.ai
 * Description: AI-powered article generator with internal links, FAQ & GEO optimization. Build calculators, timers & comparison tables.
 * Version: 2.5.2
 * Author: TalkGenAI Team
 * License: GPLv2 or later
 * Text Domain: talkgenai
 * Requires at least: 5.0
 * Tested up to: 6.9
 * Requires PHP: 7.4
 * 
 * This plugin includes Select2 v4.1.0-rc.0 (https://select2.org)
 * Licensed under the MIT License, which is GPL-compatible
 * Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit('Direct access not allowed.');
}

// Check WordPress compatibility early
if (!function_exists('register_activation_hook')) {
    // WordPress not loaded properly - exit gracefully
    return;
}

// Check PHP version compatibility
if (version_compare(PHP_VERSION, '7.4', '<')) {
    add_action('admin_notices', function() {
        $screen = get_current_screen();
        // Only show on plugins page or TalkGenAI pages
        if (!$screen || $screen->id === 'plugins' || strpos($screen->id, 'talkgenai') !== false) {
            echo '<div class="notice notice-error is-dismissible"><p><strong>TalkGenAI Error:</strong> This plugin requires PHP 7.4 or higher. You are running PHP ' . esc_html(PHP_VERSION) . '. <a href="https://wordpress.org/support/update-php/" target="_blank">Learn how to update PHP</a></p></div>';
        }
    });
    return;
}

// Check required PHP extensions
$talkgenai_required_extensions = array('curl', 'json');
foreach ($talkgenai_required_extensions as $talkgenai_extension) {
    if (!extension_loaded($talkgenai_extension)) {
        add_action('admin_notices', function() use ($talkgenai_extension) {
            $screen = get_current_screen();
            // Only show on plugins page or TalkGenAI pages
            if (!$screen || $screen->id === 'plugins' || strpos($screen->id, 'talkgenai') !== false) {
                echo '<div class="notice notice-error is-dismissible"><p><strong>TalkGenAI Error:</strong> Missing required PHP extension: ' . esc_html($talkgenai_extension) . '. Please contact your hosting provider to enable this extension.</p></div>';
            }
        });
        return;
    }
}

// Define plugin constants
define('TALKGENAI_VERSION', '2.5.2');
define('TALKGENAI_PLUGIN_URL', plugin_dir_url(__FILE__));
define('TALKGENAI_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('TALKGENAI_PLUGIN_BASENAME', plugin_basename(__FILE__));
define('TALKGENAI_PLUGIN_FILE', __FILE__);

// Security and capability constants
define('TALKGENAI_MIN_CAPABILITY', 'manage_options');
define('TALKGENAI_ADMIN_CAPABILITY', 'manage_options');
define('TALKGENAI_MAX_REQUESTS_PER_HOUR', 100);
define('TALKGENAI_REQUEST_TIMEOUT', 60);

// Debug logging removed for WordPress.org submission
// if (defined('WP_DEBUG') && WP_DEBUG) {
//     error_log('TalkGenAI: Plugin initializing...');
//     error_log('TalkGenAI: Plugin URL = ' . TALKGENAI_PLUGIN_URL);
//     error_log('TalkGenAI: Plugin Path = ' . TALKGENAI_PLUGIN_PATH);
// }

/**
 * Main TalkGenAI Plugin Class
 * Singleton pattern for single instance management
 */
class TalkGenAI_Plugin {
    
    /**
     * Single instance of the plugin
     */
    private static $instance = null;
    
    /**
     * Plugin components
     */
    private $database;
    private $api;
    private $security;
    private $file_generator;
    private $admin;
    private $job_manager;
    private $enqueued_app_assets = array();
    
    /**
     * Get single instance of plugin
     */
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Private constructor to prevent multiple instances
     */
    private function __construct() {
        // Final safety check before initialization
        if (!function_exists('wp_enqueue_script') || !function_exists('add_action')) {
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI: WordPress functions not available during plugin initialization');
            return;
        }
        
        $this->init_hooks();
        
        if (!$this->load_dependencies()) {
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI: Failed to load dependencies');
            return;
        }
        
        $this->init_components();
    }
    
    /**
     * Initialize WordPress hooks
     */
    private function init_hooks() {
        // Core WordPress hooks
        add_action('init', array($this, 'init'));
        add_action('plugins_loaded', array($this, 'load_textdomain'));
        // Safety check: Ensure database tables exist on every admin page load
        add_action('admin_init', array($this, 'ensure_database_tables'));
        // CSP support (currently disabled for WordPress compatibility)
        add_action('admin_init', function() {
            if (class_exists('TalkGenAI_Security')) {
                // For admin pages, mark CSP as potentially needed
                // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Admin page URL parameter check only, no data processing
                if (isset($_GET['page']) && strpos(sanitize_key($_GET['page']), 'talkgenai') === 0) {
                    TalkGenAI_Security::require_csp_for_request();
                    // CSP emission disabled in should_emit_csp() for compatibility
                }
            }
        });
        
        // CSP headers via wp_headers filter (currently disabled for compatibility)
        add_filter('wp_headers', function($headers) {
            if (class_exists('TalkGenAI_Security') && TalkGenAI_Security::should_emit_csp()) {
                $csp_header = TalkGenAI_Security::build_csp_header();
                $headers['Content-Security-Policy'] = $csp_header;
            }
            return $headers;
        });
        
        // Activation and deactivation hooks are registered outside the class for reliability
        
        // Admin hooks
        if (is_admin()) {
            add_action('admin_menu', array($this, 'add_admin_menu'));
            add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
            add_action('wp_ajax_talkgenai_generate_app', array($this, 'ajax_generate_app'));
            add_action('wp_ajax_talkgenai_modify_app', array($this, 'ajax_modify_app'));
            add_action('wp_ajax_talkgenai_delete_app', array($this, 'ajax_delete_app'));
            add_action('wp_ajax_talkgenai_test_connection', array($this, 'ajax_test_connection'));
            add_action('wp_ajax_talkgenai_auto_detect', array($this, 'ajax_auto_detect'));
            add_action('wp_ajax_talkgenai_debug_save_test', array($this, 'ajax_debug_save_test'));
            // Removed legacy talkgenai_simple_test debug endpoint to satisfy WordPress.org nonce verification checks
            add_action('wp_ajax_talkgenai_save_chunk', array($this, 'ajax_save_chunk'));
            add_action('wp_ajax_talkgenai_finalize_chunk', array($this, 'ajax_finalize_chunked_save'));
            add_action('wp_ajax_talkgenai_save_app', array($this, 'ajax_save_app'));
            add_action('wp_ajax_talkgenai_generate_article', array($this, 'ajax_generate_article'));
            add_action('wp_ajax_talkgenai_analyze_website', array($this, 'ajax_analyze_website'));
            add_action('wp_ajax_talkgenai_migrate_static_files', array($this, 'ajax_migrate_static_files'));
            
            // Generic Job System AJAX handlers
            add_action('wp_ajax_talkgenai_create_job', array($this, 'ajax_create_job'));
            add_action('wp_ajax_talkgenai_check_job_status', array($this, 'ajax_check_job_status'));
            add_action('wp_ajax_talkgenai_get_results_history', array($this, 'ajax_get_results_history'));
            add_action('wp_ajax_talkgenai_load_result', array($this, 'ajax_load_result'));
            add_action('wp_ajax_talkgenai_delete_result', array($this, 'ajax_delete_result'));
            add_action('wp_ajax_talkgenai_create_draft', array($this, 'ajax_create_draft'));
            add_action('wp_ajax_talkgenai_upload_article_image', array($this, 'ajax_upload_article_image'));
            add_action('wp_ajax_talkgenai_get_writing_styles', array($this, 'ajax_get_writing_styles'));
        }
        
        // Frontend hooks
        add_action('wp_enqueue_scripts', array($this, 'frontend_enqueue_scripts'));
        add_shortcode('talkgenai_app', array($this, 'render_shortcode'));
        add_action('wp_head', array($this, 'output_schema_markup'));
        
        // AJAX hooks for logged-in users
        add_action('wp_ajax_talkgenai_load_app', array($this, 'ajax_load_app'));
    }
    
    /**
     * Load plugin dependencies
     */
    private function load_dependencies() {
        
        // Core classes with error handling
        $required_files = array(
            'includes/class-talkgenai-database.php',
            'includes/class-talkgenai-api.php',
            'includes/class-talkgenai-security.php',
            'includes/class-talkgenai-file-generator.php',
            'includes/class-talkgenai-job-manager.php'
        );
        
        foreach ($required_files as $file) {
            $file_path = TALKGENAI_PLUGIN_PATH . $file;
            if (!file_exists($file_path)) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Required file missing: $file");
                add_action('admin_notices', function() use ($file) {
                    $screen = get_current_screen();
                    // Only show on plugins page or TalkGenAI pages
                    if (!$screen || $screen->id === 'plugins' || strpos($screen->id, 'talkgenai') !== false) {
                        echo '<div class="notice notice-error is-dismissible"><p><strong>TalkGenAI Error:</strong> Missing required file: ' . esc_html($file) . '. Please reinstall the plugin.</p></div>';
                    }
                });
                return false;
            }
            
            try {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Loading file: $file");
                require_once $file_path;
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Successfully loaded: $file");
            } catch (ParseError $e) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Parse error in $file: " . $e->getMessage());
                add_action('admin_notices', function() use ($file, $e) {
                    $screen = get_current_screen();
                    if (!$screen || $screen->id === 'plugins' || strpos($screen->id, 'talkgenai') !== false) {
                        echo '<div class="notice notice-error is-dismissible"><p><strong>TalkGenAI Error:</strong> Syntax error in ' . esc_html($file) . ': ' . esc_html($e->getMessage()) . '</p></div>';
                    }
                });
                return false;
            } catch (Error $e) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Fatal error in $file: " . $e->getMessage());
                add_action('admin_notices', function() use ($file, $e) {
                    $screen = get_current_screen();
                    if (!$screen || $screen->id === 'plugins' || strpos($screen->id, 'talkgenai') !== false) {
                        echo '<div class="notice notice-error is-dismissible"><p><strong>TalkGenAI Error:</strong> Fatal error in ' . esc_html($file) . ': ' . esc_html($e->getMessage()) . '</p></div>';
                    }
                });
                return false;
            } catch (Exception $e) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Exception in $file: " . $e->getMessage());
                add_action('admin_notices', function() use ($file, $e) {
                    $screen = get_current_screen();
                    if (!$screen || $screen->id === 'plugins' || strpos($screen->id, 'talkgenai') !== false) {
                        echo '<div class="notice notice-error is-dismissible"><p><strong>TalkGenAI Error:</strong> Exception in ' . esc_html($file) . ': ' . esc_html($e->getMessage()) . '</p></div>';
                    }
                });
                return false;
            }
        }
        
        // Admin classes (only in admin)
        if (is_admin()) {
            $admin_file = TALKGENAI_PLUGIN_PATH . 'includes/class-talkgenai-admin.php';
            if (!file_exists($admin_file)) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Admin class file missing");
                return false;
            }
            
            try {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Loading admin file: class-talkgenai-admin.php");
                require_once $admin_file;
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Successfully loaded admin file");
            } catch (ParseError $e) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Parse error in admin class: " . $e->getMessage());
                return false;
            } catch (Error $e) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Fatal error in admin class: " . $e->getMessage());
                return false;
            } catch (Exception $e) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Exception in admin class: " . $e->getMessage());
                return false;
            }
        }
        
        // Utility functions
        $functions_file = TALKGENAI_PLUGIN_PATH . 'includes/talkgenai-functions.php';
        if (file_exists($functions_file)) {
            try {
                require_once $functions_file;
            } catch (ParseError $e) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Parse error in functions: " . $e->getMessage());
            }
        }
        
        // All dependencies loaded successfully
        return true;
    }
    
    /**
     * Initialize plugin components
     */
    private function init_components() {
        try {
            $this->database = new TalkGenAI_Database();
            $this->api = new TalkGenAI_API();
            $this->security = new TalkGenAI_Security();
            $this->file_generator = new TalkGenAI_File_Generator();
            $this->job_manager = new TalkGenAI_Job_Manager();
            
            if (is_admin()) {
                $this->admin = new TalkGenAI_Admin($this->database, $this->api, $this->security);
            }
            
            // Initialize production monitoring
            $this->init_production_monitoring();
            
        } catch (Exception $e) {
            // Debug logging removed for WordPress.org submission
            // error_log("TalkGenAI: Critical error initializing components: " . $e->getMessage());
            
            // Deactivate plugin if critical components fail
            if (is_admin()) {
                add_action('admin_notices', function() use ($e) {
                    $screen = get_current_screen();
                    if (!$screen || $screen->id === 'plugins' || strpos($screen->id, 'talkgenai') !== false) {
                        echo '<div class="notice notice-error is-dismissible"><p>';
                        echo '<strong>' . esc_html__('TalkGenAI Plugin Error:', 'talkgenai') . '</strong> ';
                        echo esc_html__('The plugin encountered a critical error: ', 'talkgenai');
                        echo esc_html($e->getMessage());
                        echo '</p></div>';
                    }
                });
                
                deactivate_plugins(TALKGENAI_PLUGIN_BASENAME);
            }
        }
    }

    /**
     * Initialize production monitoring
     */
    private function init_production_monitoring() {
        // Schedule health checks
        if (!wp_next_scheduled('talkgenai_health_check')) {
            wp_schedule_event(time(), 'hourly', 'talkgenai_health_check');
        }
        
        // Schedule performance monitoring
        if (!wp_next_scheduled('talkgenai_performance_check')) {
            wp_schedule_event(time(), 'daily', 'talkgenai_performance_check');
        }
        
        add_action('talkgenai_health_check', [$this, 'run_health_check']);
        add_action('talkgenai_performance_check', [$this, 'run_performance_check']);
    }
    
    /**
     * Run health check
     */
    public function run_health_check() {
        try {
            $health_data = [
                'timestamp' => time(),
                'database_status' => $this->check_database_health(),
                'server_status' => $this->check_server_health(),
                'plugin_status' => $this->check_plugin_health()
            ];
            
            // Store health data
            update_option('talkgenai_health_status', $health_data);
            
            // Alert if critical issues found
            if (!$health_data['database_status']['healthy'] || !$health_data['server_status']['healthy']) {
                $this->send_health_alert($health_data);
            }
            
        } catch (Exception $e) {
            // Debug logging removed for WordPress.org submission
            // error_log("TalkGenAI: Health check failed: " . $e->getMessage());
        }
    }
    
    /**
     * Check database health
     */
    private function check_database_health() {
        global $wpdb;
        
        try {
            // Check if tables exist
            $apps_table = esc_sql($this->database->get_apps_table());
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct query needed for health monitoring
            $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $apps_table)) === $apps_table;
            
            if (!$table_exists) {
                return ['healthy' => false, 'message' => 'Database tables missing'];
            }
            
            // Check table performance
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct query needed for health monitoring
            $count = $wpdb->get_var("SELECT COUNT(*) FROM " . esc_sql($apps_table));
            $performance_ok = $count < 10000; // Alert if too many apps
            
            return [
                'healthy' => true,
                'app_count' => intval($count),
                'performance_warning' => !$performance_ok
            ];
            
        } catch (Exception $e) {
            return ['healthy' => false, 'message' => $e->getMessage()];
        }
    }
    
    /**
     * Check server health
     */
    private function check_server_health() {
        try {
            $result = $this->api->test_connection(true); // Force fresh check
            
            return [
                'healthy' => $result['success'] ?? false,
                'response_time' => $result['response_time'] ?? null,
                'message' => $result['message'] ?? 'Unknown status'
            ];
            
        } catch (Exception $e) {
            return ['healthy' => false, 'message' => $e->getMessage()];
        }
    }
    
    /**
     * Check plugin health
     */
    private function check_plugin_health() {
        $issues = [];
        
        // Check WordPress version compatibility
        if (version_compare(get_bloginfo('version'), '5.0', '<')) {
            $issues[] = 'WordPress version too old';
        }
        
        // Check PHP version
        if (version_compare(PHP_VERSION, '7.4', '<')) {
            $issues[] = 'PHP version too old';
        }
        
        // Check required extensions
        $required_extensions = ['curl', 'json', 'openssl'];
        foreach ($required_extensions as $ext) {
            if (!extension_loaded($ext)) {
                $issues[] = "Missing PHP extension: {$ext}";
            }
        }
        
        return [
            'healthy' => empty($issues),
            'issues' => $issues,
            'php_version' => PHP_VERSION,
            'wp_version' => get_bloginfo('version')
        ];
    }
    
    /**
     * Run performance check
     */
    public function run_performance_check() {
        try {
            $performance_data = [
                'timestamp' => time(),
                'memory_usage' => memory_get_peak_usage(true),
                'database_performance' => $this->check_database_performance(),
                'cache_performance' => $this->check_cache_performance()
            ];
            
            update_option('talkgenai_performance_data', $performance_data);
            
        } catch (Exception $e) {
            // Debug logging removed for WordPress.org submission
            // error_log("TalkGenAI: Performance check failed: " . $e->getMessage());
        }
    }
    
    /**
     * Check database performance
     */
    private function check_database_performance() {
        global $wpdb;
        
        $start_time = microtime(true);
        $table_name = esc_sql($this->database->get_apps_table());
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct query needed for performance monitoring
        $wpdb->get_results("SELECT COUNT(*) FROM " . esc_sql($table_name));
        $query_time = microtime(true) - $start_time;
        
        return [
            'query_time' => $query_time,
            'slow_query_warning' => $query_time > 1.0 // Warn if query takes > 1 second
        ];
    }
    
    /**
     * Check cache performance
     */
    private function check_cache_performance() {
        $cache_hits = get_option('talkgenai_cache_hits', 0);
        $cache_misses = get_option('talkgenai_cache_misses', 0);
        $total_requests = $cache_hits + $cache_misses;
        
        $hit_rate = $total_requests > 0 ? ($cache_hits / $total_requests) * 100 : 0;
        
        return [
            'hit_rate' => $hit_rate,
            'total_requests' => $total_requests,
            'performance_warning' => $hit_rate < 50 // Warn if hit rate < 50%
        ];
    }
    
    /**
     * Send health alert
     */
    private function send_health_alert($health_data) {
        // Health check emails disabled - monitoring still active in logs/options
        return;
        
        $admin_email = get_option('admin_email');
        $site_name = get_bloginfo('name');
        
        $subject = "TalkGenAI Health Alert - {$site_name}";
        $message = "TalkGenAI plugin health check detected issues:\n\n";
        
        if (!$health_data['database_status']['healthy']) {
            $message .= "Database Issue: " . $health_data['database_status']['message'] . "\n";
        }
        
        if (!$health_data['server_status']['healthy']) {
            $message .= "Server Issue: " . $health_data['server_status']['message'] . "\n";
        }
        
        $message .= "\nTime: " . gmdate('Y-m-d H:i:s') . "\n";
        $message .= "Site: " . get_site_url() . "\n";
        
        wp_mail($admin_email, $subject, $message);
    }
    
    /**
     * Initialize plugin
     */
    public function init() {
        // Load text domain for translations
        $this->load_textdomain();
        
        // Plugin initialized successfully - debug logging removed for WordPress.org submission
        // if (defined('WP_DEBUG') && WP_DEBUG) {
        //     error_log('TalkGenAI: Plugin initialized successfully');
        // }
    }
    
    /**
     * Load plugin text domain for translations
     * Note: WordPress.org automatically loads translations for hosted plugins
     */
    public function load_textdomain() {
        // WordPress.org automatically loads translations - no action needed
    }
    
    /**
     * Ensure database tables exist (safety check on admin_init)
     * This handles cases where activation hook didn't run (e.g., fresh reinstall)
     */
    public function ensure_database_tables() {
        // Only check once per page load
        static $checked = false;
        if ($checked) {
            return;
        }
        $checked = true;
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'talkgenai_apps';
        
        // Quick check if main table exists
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct query needed to check if plugin tables exist during initialization
        $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) === $table_name;
        
        if (!$table_exists) {
            // Tables missing - create them now
            if (!class_exists('TalkGenAI_Database')) {
                require_once TALKGENAI_PLUGIN_PATH . 'includes/class-talkgenai-database.php';
            }
            
            $database = new TalkGenAI_Database();
            $database->create_tables();
            
            // Show admin notice
            add_action('admin_notices', function() {
                echo '<div class="notice notice-success is-dismissible">';
                echo '<p><strong>TalkGenAI:</strong> Database tables were automatically created.</p>';
                echo '</div>';
            });
            
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI: Database tables were missing and have been created automatically');
        } else {
            // Table exists - ensure schema is up to date (automatic migration for existing customers)
            // Check for the new "sticky" column; add it if missing via dbDelta
            // Table name is safe: constructed from $wpdb->prefix (WordPress-controlled) + hardcoded suffix
            $escaped_table = esc_sql($table_name);
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- one-time migration check; not cacheable
            $sticky_exists = $wpdb->get_var(
                $wpdb->prepare(
                    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- SHOW COLUMNS requires table name interpolation; table is safe via esc_sql() on prefix-based name
                    "SHOW COLUMNS FROM `{$escaped_table}` LIKE %s",
                    'sticky'
                )
            );
            if (empty($sticky_exists)) {
                if (!class_exists('TalkGenAI_Database')) {
                    require_once TALKGENAI_PLUGIN_PATH . 'includes/class-talkgenai-database.php';
                }
                $database = new TalkGenAI_Database();
                $database->create_tables(); // dbDelta will add the missing column

                add_action('admin_notices', function() {
                    echo '<div class="notice notice-success is-dismissible">';
                    echo '<p><strong>TalkGenAI:</strong> Database schema was automatically updated.</p>';
                    echo '</div>';
                });
            }
        }
    }
    
    /**
     * Plugin activation
     */
    public function activate() {
        // Check PHP version
        if (version_compare(PHP_VERSION, '7.3', '<')) {
            deactivate_plugins(TALKGENAI_PLUGIN_BASENAME);
            wp_die(esc_html__('TalkGenAI requires PHP 7.3 or higher.', 'talkgenai'));
        }
        
        // Check WordPress version
        if (version_compare(get_bloginfo('version'), '5.0', '<')) {
            deactivate_plugins(TALKGENAI_PLUGIN_BASENAME);
            wp_die(esc_html__('TalkGenAI requires WordPress 5.0 or higher.', 'talkgenai'));
        }
        
        // Ensure database class is loaded
        if (!class_exists('TalkGenAI_Database')) {
            require_once TALKGENAI_PLUGIN_PATH . 'includes/class-talkgenai-database.php';
        }
        
        // Create database tables - CRITICAL: Plugin cannot work without these
        try {
            $database = new TalkGenAI_Database();
            $database->create_tables();
            
            // Verify tables were created successfully
            global $wpdb;
            $table_name = esc_sql($wpdb->prefix . 'talkgenai_apps');
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct query needed to verify table creation during activation
            $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) == $table_name;
            
            if (!$table_exists) {
                throw new Exception(__('Failed to create required database table: wp_talkgenai_apps', 'talkgenai'));
            }
            
        } catch (Exception $e) {
            // Database creation failed - deactivate plugin and show error
            deactivate_plugins(TALKGENAI_PLUGIN_BASENAME);
            wp_die(
                '<h1>' . esc_html__('TalkGenAI Activation Failed', 'talkgenai') . '</h1>' .
                '<p><strong>' . esc_html__('Database Error:', 'talkgenai') . '</strong> ' . esc_html($e->getMessage()) . '</p>' .
                '<p>' . esc_html__('The plugin could not create its required database tables. Please contact your hosting provider or system administrator.', 'talkgenai') . '</p>' .
                '<p><a href="' . esc_url(admin_url('plugins.php')) . '">' . esc_html__('Return to Plugins', 'talkgenai') . '</a></p>',
                esc_html__('Plugin Activation Failed', 'talkgenai'),
                array('response' => 500)
            );
        }
        
        // Set default options
        $this->set_default_options();
        
        // Flush rewrite rules
        flush_rewrite_rules();
        
        // Debug logging removed for WordPress.org submission
        // if (defined('WP_DEBUG') && WP_DEBUG) {
        //     error_log('TalkGenAI: Plugin activated successfully');
        // }
    }
    
    /**
     * Plugin deactivation
     */
    public function deactivate() {
        // Clean up temporary data
        $this->cleanup_temp_data();
        
        // Flush rewrite rules
        flush_rewrite_rules();
        
        // Debug logging removed for WordPress.org submission
        // if (defined('WP_DEBUG') && WP_DEBUG) {
        //     error_log('TalkGenAI: Plugin deactivated');
        // }
    }
    
    /**
     * Plugin uninstall (static method)
     */
    public static function uninstall() {
        // Remove all plugin data
        $database = new TalkGenAI_Database();
        $database->drop_tables();
        
        // Remove options
        delete_option('talkgenai_settings');
        delete_option('talkgenai_version');
        
        // Debug logging removed for WordPress.org submission
        // if (defined('WP_DEBUG') && WP_DEBUG) {
        //     error_log('TalkGenAI: Plugin uninstalled - all data removed');
        // }
    }
    
    /**
     * Add admin menu
     */
    public function add_admin_menu() {
        // Main menu page - defaults to Generate Articles
        add_menu_page(
            __('TalkGenAI', 'talkgenai'),
            __('TalkGenAI', 'talkgenai'),
            TALKGENAI_MIN_CAPABILITY,
            'talkgenai-articles',
            array($this->admin, 'render_articles_page'),
            'dashicons-editor-code',
            30
        );

        // Submenu pages
        add_submenu_page(
            'talkgenai-articles',
            __('Generate Articles', 'talkgenai'),
            __('Generate Articles', 'talkgenai'),
            TALKGENAI_MIN_CAPABILITY,
            'talkgenai-articles',
            array($this->admin, 'render_articles_page')
        );

        add_submenu_page(
            'talkgenai-articles',
            __('Generate App', 'talkgenai'),
            __('Generate App', 'talkgenai'),
            TALKGENAI_MIN_CAPABILITY,
            'talkgenai',
            array($this->admin, 'render_main_page')
        );

        add_submenu_page(
            'talkgenai-articles',
            __('My Apps', 'talkgenai'),
            __('My Apps', 'talkgenai'),
            TALKGENAI_MIN_CAPABILITY,
            'talkgenai-apps',
            array($this->admin, 'render_apps_page')
        );

        add_submenu_page(
            'talkgenai-articles',
            __('Settings', 'talkgenai'),
            __('Settings', 'talkgenai'),
            TALKGENAI_ADMIN_CAPABILITY,
            'talkgenai-settings',
            array($this->admin, 'render_settings_page')
        );

    }
    
    /**
     * Enqueue admin scripts and styles
     */
    public function admin_enqueue_scripts($hook) {
        // Warn before deleting the plugin (data loss prevention)
        if ($hook === 'plugins.php') {
            $warning = __( "WARNING: Deleting TalkGenAI will permanently erase ALL your apps from the database!\n\nApps already embedded in pages will still display, but they cannot be managed, edited, or duplicated.\n\nSafe reinstall: Deactivate \u2192 upload new files \u2192 Activate (no data loss).\n\nAre you sure you want to DELETE and permanently lose all app data?", 'talkgenai' );
            wp_register_script('talkgenai-delete-warning', false, array('jquery'), TALKGENAI_VERSION, true);
            wp_enqueue_script('talkgenai-delete-warning');
            wp_add_inline_script('talkgenai-delete-warning', sprintf(
                'jQuery(function($){
                    var row = $("tr[data-plugin=\'%s\']");
                    row.find("a.delete, .row-actions .delete a").on("click", function(e){
                        if (!window.confirm(%s)) { e.preventDefault(); return false; }
                    });
                });',
                esc_js(TALKGENAI_PLUGIN_BASENAME),
                wp_json_encode($warning)
            ));
            return;
        }

        // Only load on TalkGenAI admin pages
        if (strpos($hook, 'talkgenai') === false) {
            return;
        }
        
        // Enqueue Select2 from local files (WordPress compliance - no external CDNs)
        wp_enqueue_style(
            'select2-css',
            TALKGENAI_PLUGIN_URL . 'admin/assets/select2/css/select2.min.css',
            array(),
            '4.1.0'
        );
        wp_enqueue_script(
            'select2-js',
            TALKGENAI_PLUGIN_URL . 'admin/assets/select2/js/select2.min.js',
            array('jquery'),
            '4.1.0',
            true
        );
        
        // Admin CSS (no dependency to avoid breaking if Select2 fails)
        $admin_css_path = TALKGENAI_PLUGIN_PATH . 'admin/css/admin.css';
        $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : TALKGENAI_VERSION;
        wp_enqueue_style(
            'talkgenai-admin',
            TALKGENAI_PLUGIN_URL . 'admin/css/admin.css',
            array(),
            $admin_css_version
        );
        
        // Job Manager CSS
        $job_css_path = TALKGENAI_PLUGIN_PATH . 'admin/css/job-manager.css';
        $job_css_version = file_exists($job_css_path) ? filemtime($job_css_path) : TALKGENAI_VERSION;
        wp_enqueue_style(
            'talkgenai-job-manager',
            TALKGENAI_PLUGIN_URL . 'admin/css/job-manager.css',
            array(),
            $job_css_version
        );
        
        // =============================================================================
        // JOB SYSTEM: DISABLED FOR FREE TIER (uses direct generation)
        // =============================================================================
        // To enable async job system (requires Render workers + payment):
        // 1. Uncomment the job-manager and article-job sections below
        // 2. Update admin.js dependency to include 'talkgenai-job-manager'
        // 3. Uncomment localize script for job-manager
        // 4. Deploy workers on Render (see TalkGenAIService/render.yaml)
        // =============================================================================

        // Job Manager JavaScript - MongoDB-based jobs (Railway/Render with workers)
        $job_js_path = TALKGENAI_PLUGIN_PATH . 'admin/js/job-manager.js';
        $job_js_version = '2.3.HTML_FIX_' . time();
        wp_enqueue_script(
            'talkgenai-job-manager',
            TALKGENAI_PLUGIN_URL . 'admin/js/job-manager.js',
            array('jquery'),
            $job_js_version,
            true
        );
        
        // Admin JavaScript - WITH job-manager dependency (uses background jobs)
        $admin_js_path = TALKGENAI_PLUGIN_PATH . 'admin/js/admin.js';
        $admin_js_version = '2.3.HTML_FIX_' . time(); // Timestamp for absolute cache bust
        wp_enqueue_script(
            'talkgenai-admin',
            TALKGENAI_PLUGIN_URL . 'admin/js/admin.js',
            array('jquery', 'talkgenai-job-manager', 'select2-js'), // Re-added job-manager dependency
            $admin_js_version,
            true
        );
        
        // Article integration JavaScript - ENABLED (async article generation)
        $article_integration_js = TALKGENAI_PLUGIN_PATH . 'admin/js/article-job-integration.js';
        // Strong cache busting (admin pages are sensitive to stale JS during development)
        $article_integration_version = '2.3.SCHEMA_' . time();
        wp_enqueue_script(
            'talkgenai-article-job',
            TALKGENAI_PLUGIN_URL . 'admin/js/article-job-integration.js',
            array('jquery', 'talkgenai-job-manager'),
            $article_integration_version,
            true
        );
        
        // Localize script for AJAX - job-manager handles async flow
        wp_localize_script('talkgenai-job-manager', 'talkgenai_ajax', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('talkgenai_nonce'),
            'debug' => defined('WP_DEBUG') && WP_DEBUG ? 1 : 0,
            'strings' => array(
                'generating' => __('Generating app...', 'talkgenai'),
                'error' => __('An error occurred. Please try again.', 'talkgenai'),
                'success' => __('App generated successfully!', 'talkgenai'),
                'confirm_delete' => __('Are you sure you want to delete this app?', 'talkgenai')
            )
        ));

        // Expose a simple global nonce for scripts that expect `talkgenai_nonce`
        wp_add_inline_script(
            'talkgenai-job-manager', // Changed back to job-manager (enabled for workers)
            'window.talkgenai_nonce = ' . wp_json_encode( wp_create_nonce('talkgenai_nonce') ) . ';',
            'before'
        );

        // Note: we do not override existing handlers; integration script only populates existing UI containers
    }
    
    /**
     * Enqueue frontend scripts and styles
     */
    public function frontend_enqueue_scripts() {
        // Only enqueue if shortcode is present
        global $post;
        if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'talkgenai_app')) {
            // Mark CSP required for this request
            if (class_exists('TalkGenAI_Security')) {
                TalkGenAI_Security::require_csp_for_request();
            }
            wp_enqueue_style(
                'talkgenai-frontend',
                TALKGENAI_PLUGIN_URL . 'public/css/frontend.css',
                array(),
                TALKGENAI_VERSION
            );

            // Detect app IDs in content and enqueue per-app assets early (in head)
            $app_ids = $this->extract_app_ids_from_content($post->post_content);
            if (!empty($app_ids)) {
                $this->enqueue_app_assets_for_ids($app_ids);
            }
        }
    }
    
    /**
     * Render shortcode (with enhanced error handling)
     */
    public function render_shortcode($atts) {
        try {
            $atts = shortcode_atts(array(
                'id' => 0,
                'container_class' => 'talkgenai-app-container',
                'fallback_message' => ''
            ), $atts, 'talkgenai_app');
            
            $app_id = intval($atts['id']);
            if (!$app_id) {
                return $this->render_error_fallback(__('Invalid app ID.', 'talkgenai'), $atts);
            }
            
            // Try to get app with error handling
            $app = $this->database->get_app($app_id);
            if (!$app) {
                return $this->render_error_fallback(__('App not found.', 'talkgenai'), $atts);
            }
            
            // Check if app is archived or inactive
            if (isset($app['status']) && $app['status'] !== 'active') {
                return $this->render_error_fallback(__('App is not available.', 'talkgenai'), $atts);
            }
            
            // Security validation with graceful degradation (including CSS)
            try {
                // Build content for validation including CSS
                $css_content = $app['css_content'] ?? '';
                $combined_content_for_validation = $app['html_content'] . $css_content;
                
                if (!$this->security->validate_app_content(
                    $combined_content_for_validation, 
                    $app['js_content'] ?? '', 
                    $app['json_spec'], 
                    $app['security_hash']
                )) {
                    // Log security failure but show fallback instead of error - debug logging removed for WordPress.org submission
                    // error_log("TalkGenAI: Security validation failed for app {$app_id}");
                    return $this->render_error_fallback(__('App temporarily unavailable.', 'talkgenai'), $atts);
                }
            } catch (Exception $e) {
                // Debug logging removed for WordPress.org submission
                // error_log("TalkGenAI: Security validation exception for app {$app_id}: " . $e->getMessage());
                return $this->render_error_fallback(__('App temporarily unavailable.', 'talkgenai'), $atts);
            }
            
            // Regenerate static files if missing
            if (empty($app['css_file_url']) || empty($app['js_file_url'])) {
                // Debug logging removed for WordPress.org submission
                // if (defined('WP_DEBUG') && WP_DEBUG) {
                //     error_log("TalkGenAI: Regenerating missing static files for app {$app_id}");
                // }
                $file_results = $this->file_generator->regenerate_if_missing($app_id, $app);
                if (!is_wp_error($file_results)) {
                    $app['css_file_url'] = $file_results['css_url'];
                    $app['js_file_url'] = $file_results['js_url'];
                    $app['file_version'] = $file_results['version'];
                }
            }
            
            // Enqueue static CSS file
            $css_handle = 'talkgenai-app-css-' . intval($app_id);
            if (!empty($app['css_file_url'])) {
                try {
                    $ver = !empty($app['file_version']) ? $app['file_version'] : TALKGENAI_VERSION;
                    wp_enqueue_style($css_handle, $app['css_file_url'], array(), $ver);
                } catch (Exception $e) {
                    // Debug logging removed for WordPress.org submission
                    // error_log("TalkGenAI: CSS enqueue failed for app {$app_id}: " . $e->getMessage());
                }
            } else {
                // If no CSS file, register an empty style handle for critical CSS
                wp_register_style($css_handle, false, array(), TALKGENAI_VERSION);
                wp_enqueue_style($css_handle);
            }
            
            // Add inline CSS content if available (WordPress compliance)
            if (!empty($app['css_content'])) {
                wp_add_inline_style($css_handle, wp_strip_all_tags($app['css_content']));
            }
            
            // Minimal critical CSS to ensure readable layout during initial load
            // Note: Inline critical CSS is necessary for above-the-fold rendering performance
            // This prevents flash of unstyled content (FOUC) before external CSS loads
            static $printed_critical = array();
            if (empty($printed_critical[$app_id])) {
                $critical_css = '.talkgenai-app-container{max-width:1200px;margin:16px auto;padding:0 12px}.talkgenai-app-container .calculator-container{max-width:1200px;margin:0 auto}.talkgenai-app-container .calculator-header{margin:8px 0 16px;padding:12px;border-radius:8px;background:#f8f9fa}.talkgenai-app-container .calculator-title{font-size:1.6rem;font-weight:600;color:#2E7D32;margin:0 0 6px}.talkgenai-app-container .calculator-description{font-size:0.95rem;color:#66BB6A;max-width:640px;margin:0 auto}.talkgenai-app-container .calculator-main-content{display:grid;grid-template-columns:1fr 1fr;gap:12px}@media(max-width:768px){.talkgenai-app-container .calculator-main-content{grid-template-columns:1fr}}.talkgenai-app-container .form-card,.talkgenai-app-container .results-card{background:#fff;border:1px solid #e1e8ed;border-radius:8px;padding:12px}.talkgenai-app-container .section-title{font-size:1.05rem;font-weight:600;color:#2E7D32;margin:0 0 10px;padding-bottom:4px;border-bottom:2px solid #2E7D32}.talkgenai-app-container .form-label{display:block;font-weight:500;color:#1B5E20;margin:0 0 6px;font-size:.9rem}.talkgenai-app-container .form-control, .talkgenai-app-container select{width:100%;padding:8px 10px;border:1px solid #e1e8ed;border-radius:6px;background:#fafbfc;font-size:.95rem}.talkgenai-app-container #calculateBtn,.talkgenai-app-container .btn-calculate{display:block;width:100%;margin-top:10px;padding:10px;border-radius:6px;background:#4CAF50;color:#fff;font-weight:600;border:none;cursor:pointer}';
                // Use wp_add_inline_style() for WordPress compliance
                wp_add_inline_style($css_handle, $critical_css);
                $printed_critical[$app_id] = true;
            }
            
            // Enqueue static JavaScript file
            $js_handle = 'talkgenai-app-' . intval($app_id);
            if (!empty($app['js_file_url'])) {
                try {
                    $ver = !empty($app['file_version']) ? $app['file_version'] : TALKGENAI_VERSION;
                    wp_enqueue_script($js_handle, $app['js_file_url'], array(), $ver, true);
                } catch (Exception $e) {
                    // Debug logging removed for WordPress.org submission
                    // error_log("TalkGenAI: JavaScript enqueue failed for app {$app_id}: " . $e->getMessage());
                }
            } elseif (!empty($app['js_content'])) {
                // Fallback: Enqueue inline JavaScript using wp_add_inline_script()
                wp_register_script($js_handle, false, array(), TALKGENAI_VERSION, true);
                wp_enqueue_script($js_handle);
                wp_add_inline_script($js_handle, $app['js_content']);
            }
            
            // Render app HTML only (CSS and JS enqueued separately)
            return sprintf(
                '<div class="%s" data-app-id="%d" data-app-status="active">%s</div>',
                esc_attr($atts['container_class']),
                $app_id,
                $app['html_content'] // Already sanitized when stored
            );
            
        } catch (Exception $e) {
            // Log unexpected errors - debug logging removed for WordPress.org submission
            // error_log("TalkGenAI: Unexpected error in shortcode render: " . $e->getMessage());
            return $this->render_error_fallback(__('App could not be loaded.', 'talkgenai'), $atts);
        }
    }
    
    /**
     * Render error fallback for shortcode
     */
    private function render_error_fallback($message, $atts) {
        // Use custom fallback message if provided
        if (!empty($atts['fallback_message'])) {
            $message = esc_html($atts['fallback_message']);
        }
        
        // Return a styled error container that matches the expected structure
        return sprintf(
            '<div class="%s talkgenai-error" data-app-status="error">
                <div class="talkgenai-error-message">
                    <p>%s</p>
                    <small>%s</small>
                </div>
            </div>',
            esc_attr($atts['container_class']),
            esc_html($message),
            esc_html__('Please contact the site administrator if this problem persists.', 'talkgenai')
        );
    }
    /**
     * Extract app IDs from post content where shortcode is used
     */
    private function extract_app_ids_from_content($content) {
        $ids = array();
        if (!is_string($content) || $content === '') {
            return $ids;
        }
        if (preg_match_all('/\[talkgenai_app[^\]]*id\s*=\s*\"?(\d+)\"?[^\]]*\]/i', $content, $matches)) {
            foreach ($matches[1] as $id) {
                $id_int = intval($id);
                if ($id_int > 0) {
                    $ids[$id_int] = true;
                }
            }
        }
        return array_keys($ids);
    }

    /**
     * Enqueue per-app CSS and JS early (in head) for the given IDs
     */
    private function enqueue_app_assets_for_ids($app_ids) {
        if (!is_array($app_ids) || empty($app_ids)) {
            return;
        }
        foreach ($app_ids as $app_id) {
            $app_id = intval($app_id);
            if ($app_id <= 0 || isset($this->enqueued_app_assets[$app_id])) {
                continue;
            }
            $app = $this->database ? $this->database->get_app($app_id) : null;
            if (!is_array($app) || empty($app)) {
                continue;
            }
            
            // Regenerate static files if missing
            if (empty($app['css_file_url']) || empty($app['js_file_url'])) {
                $file_results = $this->file_generator->regenerate_if_missing($app_id, $app);
                if (!is_wp_error($file_results)) {
                    $app['css_file_url'] = $file_results['css_url'];
                    $app['js_file_url'] = $file_results['js_url'];
                    $app['file_version'] = $file_results['version'];
                }
            }
            
            // Enqueue static CSS file
            if (!empty($app['css_file_url'])) {
                $handle = 'talkgenai-app-css-' . $app_id;
                $ver = !empty($app['file_version']) ? $app['file_version'] : TALKGENAI_VERSION;
                wp_register_style($handle, $app['css_file_url'], array(), $ver);
                wp_enqueue_style($handle);
            }
            
            // Enqueue static JS file
            if (!empty($app['js_file_url'])) {
                $handle = 'talkgenai-app-' . $app_id;
                $ver = !empty($app['file_version']) ? $app['file_version'] : TALKGENAI_VERSION;
                $deps = array();
                if ($this->js_uses_jquery($app['js_content'])) {
                    $deps[] = 'jquery';
                    wp_enqueue_script('jquery');
                }
                wp_register_script($handle, $app['js_file_url'], $deps, $ver, true);
                if (function_exists('wp_script_add_data')) {
                    wp_script_add_data($handle, 'defer', true);
                }
                wp_enqueue_script($handle);
            }
            $this->enqueued_app_assets[$app_id] = true;
        }
    }

    /**
     * Heuristic to detect if JS uses jQuery
     */
    private function js_uses_jquery($js_content) {
        if (!is_string($js_content) || $js_content === '') {
            return false;
        }
        // Quick check for common jQuery invocation patterns
        return (bool) preg_match('/(^|[^\w])jQuery\s*\(|(^|[^\w])\$\s*\(/', $js_content);
    }
    
    /**
     * AJAX: Generate new app
     */
    public function ajax_generate_app() {
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_die(esc_html__('Security check failed.', 'talkgenai'));
        }
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_die(esc_html__('Insufficient permissions.', 'talkgenai'));
        }
        
        // Check if admin component is loaded
        if (!$this->admin) {
            wp_die(esc_html__('Plugin not properly initialized.', 'talkgenai'));
        }
        
        // Delegate to admin class
        $this->admin->handle_generate_app();
    }
    
    /**
     * AJAX: Modify existing app
     */
    public function ajax_modify_app() {
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_die(esc_html__('Security check failed.', 'talkgenai'));
        }
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_die(esc_html__('Insufficient permissions.', 'talkgenai'));
        }
        
        // Check if admin component is loaded
        if (!$this->admin) {
            wp_die(esc_html__('Plugin not properly initialized.', 'talkgenai'));
        }
        
        // Delegate to admin class
        $this->admin->handle_modify_app();
    }
    
    /**
     * AJAX: Delete app
     */
    public function ajax_delete_app() {
        // Clean output buffer to prevent notices from breaking JSON
        if (ob_get_level()) {
            ob_clean();
        }
        
        // Debug logging removed for WordPress.org compliance
        
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI AJAX ERROR: Nonce verification failed');
            // error_log('TalkGenAI AJAX ERROR: Received nonce: ' . (isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : 'NOT SET'));
            wp_send_json_error(array('message' => __('Security check failed.', 'talkgenai')));
            return;
        }
        
        // Debug logging removed for WordPress.org submission
        // error_log('TalkGenAI AJAX: Nonce verified successfully');
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI AJAX ERROR: Insufficient permissions');
            wp_send_json_error(array('message' => __('Insufficient permissions.', 'talkgenai')));
            return;
        }
        
        // Debug logging removed for WordPress.org submission
        // error_log('TalkGenAI AJAX: Permissions checked successfully');
        // error_log('TalkGenAI AJAX: Delegating to admin->handle_delete_app()');
        
        // Delegate to admin class
        $this->admin->handle_delete_app();
    }
    
    /**
     * AJAX: Migrate all apps to static files
     */
    public function ajax_migrate_static_files() {
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_send_json_error(array('message' => 'Security check failed'));
            return;
        }
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
            return;
        }
        
        // Delegate to admin class
        $this->admin->handle_migrate_static_files();
    }
    
    /**
     * AJAX: Test server connection
     */
    public function ajax_test_connection() {
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_die(esc_html__('Security check failed.', 'talkgenai'));
        }
        
        if (!current_user_can(TALKGENAI_ADMIN_CAPABILITY)) {
            wp_die(esc_html__('Insufficient permissions.', 'talkgenai'));
        }
        
        // Delegate to admin class
        $this->admin->handle_test_connection();
    }
    
    /**
     * AJAX: Auto-detect local server
     */
    public function ajax_auto_detect() {
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_die(esc_html__('Security check failed.', 'talkgenai'));
        }
        
        if (!current_user_can(TALKGENAI_ADMIN_CAPABILITY)) {
            wp_die(esc_html__('Insufficient permissions.', 'talkgenai'));
        }
        
        // Delegate to admin class
        $this->admin->handle_auto_detect();
    }
    

    /**
     * AJAX: Debug save test
     */
    public function ajax_debug_save_test() {
        // Debug logging removed for WordPress.org submission
        // error_log('TalkGenAI DEBUG: ajax_debug_save_test() called');
        
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_die(esc_html__('Security check failed.', 'talkgenai'));
        }
        
        if (!current_user_can(TALKGENAI_ADMIN_CAPABILITY)) {
            wp_die(esc_html__('Insufficient permissions.', 'talkgenai'));
        }
        
        // Check if admin component is loaded
        if (!$this->admin) {
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI ERROR: Admin component not loaded');
            wp_die(esc_html__('Plugin not properly initialized.', 'talkgenai'));
        }
        
        // Delegate to admin class
        $this->admin->handle_debug_save_test();
    }
    
    /**
     * AJAX: Save chunk (for chunked uploads)
     */
    public function ajax_save_chunk() {
        // Debug logging removed for WordPress.org submission
        // error_log('TalkGenAI CHUNK: ajax_save_chunk() wrapper called (JSON POST version)');
        
        // SKIP security checks here - delegated handler reads JSON from php://input and verifies nonce
        // (We're receiving JSON POST, not form-encoded data, so $_POST is empty)
        
        // Check if admin component is loaded
        if (!$this->admin) {
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI ERROR: Admin component not loaded');
            wp_send_json_error(array('message' => __('Plugin not properly initialized.', 'talkgenai')));
            return;
        }
        
        // Delegate to admin class which reads from php://input
        $this->admin->handle_save_chunk();
    }

    /**
     * AJAX: Finalize chunked save
     */
    public function ajax_finalize_chunked_save() {
        // Debug logging removed for WordPress.org submission
        // error_log('TalkGenAI FINALIZE: ajax_finalize_chunked_save() wrapper called (JSON POST version)');
        
        // SKIP security checks here - delegated handler reads JSON from php://input and verifies nonce
        // (We're receiving JSON POST, not form-encoded data, so $_POST is empty)
        
        // Check if admin component is loaded
        if (!$this->admin) {
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI ERROR: Admin component not loaded');
            wp_send_json_error(array('message' => __('Plugin not properly initialized.', 'talkgenai')));
            return;
        }
        
        // Delegate to admin class which reads from php://input
        $this->admin->handle_finalize_chunked_save();
    }

    /**
     * AJAX: Save app
     */
    public function ajax_save_app() {
        // Debug logging removed for WordPress.org submission
        // error_log('TalkGenAI MAIN: ajax_save_app() entry point reached');
        // error_log('TalkGenAI MAIN: POST data size: ' . (isset($_SERVER['CONTENT_LENGTH']) ? sanitize_text_field(wp_unslash($_SERVER['CONTENT_LENGTH'])) : 'unknown') . ' bytes');
        
        // Check if admin component is loaded
        if (!$this->admin) {
            // Debug logging removed for WordPress.org submission
            // error_log('TalkGenAI ERROR: Admin component not loaded');
            wp_die(esc_html__('Plugin not properly initialized.', 'talkgenai'));
        }
        // Security and permissions are validated within admin handler
        $this->admin->handle_save_app();
    }
    
    /**
     * AJAX: Update existing app (title/description/content)
     */
    public function ajax_update_app() {
        // Check if admin component is loaded
        if (!$this->admin) {
            wp_die(esc_html__('Plugin not properly initialized.', 'talkgenai'));
        }
        // Security and permissions are validated within admin handler
        $this->admin->handle_update_app();
    }
    
    /**
     * AJAX: Load app data
     */
    public function ajax_load_app() {
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_die(esc_html__('Security check failed.', 'talkgenai'));
        }
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_die(esc_html__('Insufficient permissions.', 'talkgenai'));
        }
        
        // Delegate to admin class
        $this->admin->handle_load_app();
    }
    
    /**
     * AJAX: Generate article
     */
    public function ajax_generate_article() {
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_die(esc_html__('Security check failed.', 'talkgenai'));
        }
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_die(esc_html__('Insufficient permissions.', 'talkgenai'));
        }
        
        // Check if admin component is loaded
        if (!$this->admin) {
            wp_die(esc_html__('Plugin not properly initialized.', 'talkgenai'));
        }
        
        // Delegate to admin class
        $this->admin->handle_generate_article();
    }
    
    /**
     * AJAX: Analyze website
     */
    public function ajax_analyze_website() {
        // Security check
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'talkgenai_nonce')) {
            wp_die(esc_html__('Security check failed.', 'talkgenai'));
        }
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_die(esc_html__('Insufficient permissions.', 'talkgenai'));
        }
        
        // Check if admin component is loaded
        if (!$this->admin) {
            wp_die(esc_html__('Plugin not properly initialized.', 'talkgenai'));
        }
        
        // Delegate to admin class
        $this->admin->handle_analyze_website();
    }
    
    /**
     * AJAX: Create Job (Generic)
     */
    public function ajax_create_job() {
        check_ajax_referer('talkgenai_nonce', 'nonce');
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
        }
        
        $job_type = isset($_POST['job_type']) ? sanitize_text_field(wp_unslash($_POST['job_type'])) : '';
        
        // Parse and sanitize input_data (WordPress.org requirement: sanitize json_decode output)
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Will be sanitized after json_decode
        $input_data_raw = isset($_POST['input_data']) ? wp_unslash($_POST['input_data']) : array();
        
        // Decode JSON if string, otherwise use as-is
        if (is_string($input_data_raw) && !empty($input_data_raw)) {
            $decoded = json_decode($input_data_raw, true);
            // Sanitize decoded JSON data (WordPress.org requirement)
            $input_data = ($decoded !== null && is_array($decoded)) ? $this->sanitize_input_data_array($decoded) : array();
        } else {
            $input_data = is_array($input_data_raw) ? $this->sanitize_input_data_array($input_data_raw) : array();
        }

        // Server-side premium guard: strip create_image for free users
        if (!empty($input_data['create_image'])) {
            $user_stats = $this->api->get_user_stats();
            $user_plan = 'free';
            $bonus_credits = 0;
            if (isset($user_stats['success']) && $user_stats['success'] && isset($user_stats['data'])) {
                $user_plan = isset($user_stats['data']['plan']) ? $user_stats['data']['plan'] : 'free';
                $bonus_credits = isset($user_stats['data']['bonus_credits']) ? intval($user_stats['data']['bonus_credits']) : 0;
            }
            $is_free = ($user_plan === 'free' && $bonus_credits <= 0);
            if ($is_free) {
                unset($input_data['create_image']);
            }
        }

        // Add internal link candidates for article jobs (posts/pages only), unless already provided
        if ($job_type === 'article') {
            $auto_internal = isset($input_data['auto_internal_links']) ? (bool) $input_data['auto_internal_links'] : true;
            $has_candidates = isset($input_data['internal_link_candidates']) && is_array($input_data['internal_link_candidates']) && !empty($input_data['internal_link_candidates']);
            if (!$has_candidates && $auto_internal && function_exists('talkgenai_get_internal_link_candidates')) {
                // Prefer article_title/topic from unified form, fallback to app_title/app_description
                $t = isset($input_data['article_title']) ? $input_data['article_title'] : (isset($input_data['app_title']) ? $input_data['app_title'] : (isset($input_data['title']) ? $input_data['title'] : ''));
                $d = isset($input_data['topic']) ? $input_data['topic'] : (isset($input_data['app_description']) ? $input_data['app_description'] : (isset($input_data['description']) ? $input_data['description'] : ''));
                $cands = talkgenai_get_internal_link_candidates($t, $d, 60);
                if (is_array($cands) && !empty($cands)) {
                    $input_data['internal_link_candidates'] = $cands;
                }
            }
        }

        // Add internal link candidates for standalone_article jobs when auto_internal_links is enabled
        if ($job_type === 'standalone_article') {
            $auto_internal = isset($input_data['auto_internal_links']) ? (bool) $input_data['auto_internal_links'] : true;
            if ($auto_internal && function_exists('talkgenai_get_internal_link_candidates')) {
                $t = isset($input_data['article_title']) ? $input_data['article_title'] : '';
                $d = isset($input_data['topic']) ? $input_data['topic'] : '';
                $cands = talkgenai_get_internal_link_candidates($t, $d, 60);
                if (is_array($cands) && !empty($cands)) {
                    $input_data['internal_link_candidates'] = $cands;
                }
            }
        }
        
        // Debug logging removed for WordPress.org compliance (no unsanitized array data in logs)
        
        if (empty($job_type)) {
            wp_send_json_error(array('message' => 'Job type is required'));
        }
        
        $result = $this->job_manager->create_job(
            $job_type,
            get_current_user_id(),
            $input_data
        );
        
        if (isset($result['success']) && $result['success']) {
            // Remove the 'success' key to avoid double-wrapping
            unset($result['success']);
            wp_send_json_success($result);
        } else {
            // Check if this is a structured error with ai_message (e.g., unsupported app type)
            if (isset($result['error']) && isset($result['ai_message'])) {
                // Pass through the complete structured error
                wp_send_json_error($result);
            } else {
                // Generic error handling
                wp_send_json_error(array('message' => $result['error'] ?? 'Unknown error'));
            }
        }
    }
    
    /**
     * AJAX: Check Job Status
     */
    public function ajax_check_job_status() {
        check_ajax_referer('talkgenai_nonce', 'nonce');
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
        }
        
        $job_id = isset($_POST['job_id']) ? sanitize_text_field(wp_unslash($_POST['job_id'])) : '';
        
        if (empty($job_id)) {
            wp_send_json_error(array('message' => 'Job ID is required'));
        }
        
        $status = $this->job_manager->check_job_status($job_id);
        
        // For completed jobs with large results, bypass WordPress JSON functions
        if (isset($status['status']) && $status['status'] === 'completed' && isset($status['result'])) {
            // Increase limits for large job results (@ suppression is intentional to handle restricted hosting)
            // phpcs:ignore WordPress.PHP.IniSet.memory_limit_Blacklisted, WordPress.PHP.IniSet.display_errors_Blacklisted, Squiz.PHP.DiscouragedFunctions.Discouraged -- Necessary for handling large AI-generated content; @ suppression handles restricted hosting environments
            @ini_set('memory_limit', '256M'); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged
            @ini_set('display_errors', '0'); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged
            
            // Clear any existing output buffers
            while (ob_get_level()) {
                ob_end_clean();
            }
            
            // Start fresh with large buffer
            ob_start();
            
            // Set headers
            header('Content-Type: application/json; charset=utf-8');
            status_header(200);
            nocache_headers();
            
            // Output JSON directly
            echo wp_json_encode(array('success' => true, 'data' => $status), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            
            // Flush and exit
            ob_end_flush();
            exit;
        }
        
        wp_send_json_success($status);
    }
    
    /**
     * AJAX: Get Results History
     */
    public function ajax_get_results_history() {
        check_ajax_referer('talkgenai_nonce', 'nonce');
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
        }
        
        $job_type = isset($_POST['job_type']) ? sanitize_text_field(wp_unslash($_POST['job_type'])) : null;
        $limit = isset($_POST['limit']) ? intval($_POST['limit']) : 50;
        
        $results = $this->job_manager->get_user_results(
            get_current_user_id(),
            $job_type,
            $limit
        );
        
        wp_send_json_success($results);
    }
    
    /**
     * AJAX: Load Result
     */
    public function ajax_load_result() {
        check_ajax_referer('talkgenai_nonce', 'nonce');
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
        }
        
        // Job IDs are strings like "job_abc123", not integers
        $result_id = isset($_POST['result_id']) ? sanitize_text_field(wp_unslash($_POST['result_id'])) : '';
        
        if (empty($result_id)) {
            wp_send_json_error(array('message' => 'Result ID is required'));
        }
        
        $result = $this->job_manager->get_result($result_id);
        
        if (isset($result['success']) && $result['success']) {
            // Remove the 'success' key to avoid double-wrapping
            unset($result['success']);
            wp_send_json_success($result);
        } else {
            wp_send_json_error(array('message' => $result['error'] ?? 'Unknown error'));
        }
    }
    
    /**
     * AJAX: Delete Result
     */
    public function ajax_delete_result() {
        check_ajax_referer('talkgenai_nonce', 'nonce');
        
        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
        }
        
        // Job IDs are strings like "job_abc123", not integers
        $result_id = isset($_POST['result_id']) ? sanitize_text_field(wp_unslash($_POST['result_id'])) : '';
        
        if (empty($result_id)) {
            wp_send_json_error(array('message' => 'Result ID is required'));
        }
        
        $result = $this->job_manager->delete_result(
            $result_id,
            get_current_user_id()
        );
        
        if (isset($result['success']) && $result['success']) {
            // Remove the 'success' key to avoid double-wrapping
            unset($result['success']);
            wp_send_json_success($result);
        } else {
            wp_send_json_error(array('message' => $result['error'] ?? 'Unknown error'));
        }
    }
    
    /**
     * Output JSON-LD schema markup in wp_head for posts/pages created by TalkGenAI
     */
    public function output_schema_markup() {
        if (!is_singular()) {
            return;
        }

        $post_id = get_the_ID();
        if (!$post_id) {
            return;
        }

        $schema_blocks = get_post_meta($post_id, '_talkgenai_schema_markup', true);
        if (empty($schema_blocks) || !is_array($schema_blocks)) {
            return;
        }

        foreach ($schema_blocks as $json) {
            // Validate it's proper JSON before outputting
            $decoded = json_decode($json, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                echo '<script type="application/ld+json">' . wp_json_encode($decoded, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '</script>' . "\n";
            }
        }
    }

    /**
     * AJAX handler: Create a WordPress draft post/page from generated article
     */
    public function ajax_create_draft() {
        check_ajax_referer('talkgenai_nonce', 'nonce');

        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
        }

        $this->admin->handle_create_draft();
    }

    /**
     * AJAX handler: Upload generated article image to WP Media Library
     */
    public function ajax_upload_article_image() {
        check_ajax_referer('talkgenai_nonce', 'nonce');

        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
        }

        $job_id = isset($_POST['job_id']) ? sanitize_text_field(wp_unslash($_POST['job_id'])) : '';
        if (empty($job_id)) {
            wp_send_json_error(array('message' => 'Job ID is required'));
        }

        // Increase memory limit for large base64 image data
        // phpcs:ignore WordPress.PHP.IniSet.memory_limit_Blacklisted, Squiz.PHP.DiscouragedFunctions.Discouraged
        @ini_set('memory_limit', '256M');

        // Fetch job status (includes result.json_spec.generated_image)
        $status = $this->job_manager->check_job_status($job_id);

        if (!isset($status['status']) || $status['status'] !== 'completed') {
            wp_send_json_error(array('message' => 'Job is not completed or not found'));
        }

        // Drill into result.json_spec.generated_image
        $generated_image = null;
        if (isset($status['result']['json_spec']['generated_image'])) {
            $generated_image = $status['result']['json_spec']['generated_image'];
        }

        if (empty($generated_image) || empty($generated_image['data'])) {
            wp_send_json_error(array('message' => 'No generated image found for this job'));
        }

        $b64_data  = $generated_image['data'];
        $mime_type = isset($generated_image['mime_type']) ? $generated_image['mime_type'] : 'image/webp';
        $alt_text  = isset($generated_image['alt']) ? sanitize_text_field($generated_image['alt']) : '';
        // Fallback: never leave alt empty — use job ID as a last resort.
        if (!$alt_text) {
            $alt_text = sanitize_text_field('Article featured image');
        }
        $ext_map   = array('image/webp' => 'webp', 'image/jpeg' => 'jpg', 'image/png' => 'png');
        $ext       = isset($ext_map[$mime_type]) ? $ext_map[$mime_type] : 'webp';

        // Decode base64 to binary
        // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
        $image_bytes = base64_decode($b64_data, true);
        if ($image_bytes === false) {
            wp_send_json_error(array('message' => 'Failed to decode image data'));
        }

        // Write to temp file using WP helper
        $tmp_file = wp_tempnam('tgai-image');
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
        $bytes_written = file_put_contents($tmp_file, $image_bytes);
        if ($bytes_written === false) {
            wp_send_json_error(array('message' => 'Failed to write temporary image file'));
        }

        // Include required WP functions
        if (!function_exists('media_handle_sideload')) {
            require_once ABSPATH . 'wp-admin/includes/image.php';
            require_once ABSPATH . 'wp-admin/includes/file.php';
            require_once ABSPATH . 'wp-admin/includes/media.php';
        }

        // Prepare sideload parameters
        $file_array = array(
            'name'     => 'tgai-article-image-' . $job_id . '.' . $ext,
            'tmp_name' => $tmp_file,
        );

        $attachment_id = media_handle_sideload($file_array, 0, $alt_text);

        // Clean up temp file if still exists
        if (file_exists($tmp_file)) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
            @unlink($tmp_file);
        }

        if (is_wp_error($attachment_id)) {
            wp_send_json_error(array('message' => $attachment_id->get_error_message()));
        }

        // Set alt text and title on attachment (title mirrors alt)
        if ($alt_text) {
            update_post_meta($attachment_id, '_wp_attachment_image_alt', $alt_text);
            wp_update_post(array(
                'ID'         => $attachment_id,
                'post_title' => $alt_text,
            ));
        }

        $attachment_url = wp_get_attachment_url($attachment_id);

        // Image is now in WP Media Library — strip the base64 blob from MongoDB to save space.
        // Fire-and-forget: failure is non-fatal.
        $this->job_manager->clear_job_image_data($job_id);

        wp_send_json_success(array(
            'attachment_id' => $attachment_id,
            'url'           => $attachment_url,
            'alt'           => $alt_text,
        ));
    }

    /**
     * AJAX: Get writing styles (brand voices) filtered by current site domain
     */
    public function ajax_get_writing_styles() {
        check_ajax_referer('talkgenai_nonce', 'nonce');

        if (!current_user_can(TALKGENAI_MIN_CAPABILITY)) {
            wp_send_json_error(array('message' => 'Insufficient permissions'));
        }

        $domain = get_site_url();
        $result = $this->api->get_writing_styles($domain);

        if (is_wp_error($result)) {
            wp_send_json_error(array('message' => $result->get_error_message()));
        }

        wp_send_json_success($result);
    }

    /**
     * Set default plugin options
     */
    private function set_default_options() {
        $default_settings = array(
            'server_mode' => 'local',
            'local_server_url' => 'http://localhost:8000',
            'remote_server_url' => '',
            'remote_api_key' => '',
            'max_requests_per_hour' => TALKGENAI_MAX_REQUESTS_PER_HOUR,
            'enable_debug_logging' => false,
            'last_server_health_check' => '',
            'plugin_version' => TALKGENAI_VERSION
        );
        
        add_option('talkgenai_settings', $default_settings);
        add_option('talkgenai_version', TALKGENAI_VERSION);
    }
    
    /**
     * Clean up temporary data
     */
    private function cleanup_temp_data() {
        // Clean up any temporary files or cache
        wp_cache_delete('talkgenai_server_status');
        
        // Clean up transients
        delete_transient('talkgenai_server_health');
    }
    
    /**
     * Get plugin component
     */
    public function get_database() {
        return $this->database;
    }
    
    public function get_api() {
        return $this->api;
    }
    
    public function get_security() {
        return $this->security;
    }
    
    public function get_admin() {
        return $this->admin;
    }
    
    /**
     * Sanitize complex input data arrays (WordPress.org requirement)
     * Recursively sanitize nested arrays from json_decode()
     */
    private function sanitize_input_data_array($data) {
        if (!is_array($data)) {
            return sanitize_text_field($data);
        }
        
        $sanitized = array();
        foreach ($data as $key => $value) {
            // CRITICAL: sanitize_key() lowercases everything, breaking appClass/appType
            // Use preg_replace to preserve camelCase while still sanitizing
            $safe_key = preg_replace('/[^a-zA-Z0-9_]/', '', $key);
            
            if (is_array($value)) {
                $sanitized[$safe_key] = $this->sanitize_input_data_array($value);
            } elseif (is_string($value)) {
                // Keep long strings for AI prompts/descriptions (don't truncate)
                $sanitized[$safe_key] = sanitize_textarea_field($value);
            } elseif (is_numeric($value)) {
                $sanitized[$safe_key] = $value;
            } elseif (is_bool($value)) {
                $sanitized[$safe_key] = (bool) $value;
            } else {
                $sanitized[$safe_key] = null;
            }
        }
        
        return $sanitized;
    }
}

/**
 * Initialize the plugin
 */
function talkgenai_init() {
    return TalkGenAI_Plugin::get_instance();
}

// Start the plugin
add_action('plugins_loaded', 'talkgenai_init');

/**
 * Plugin activation function - called directly by WordPress
 */
function talkgenai_activate() {
    // Check PHP version
    if (version_compare(PHP_VERSION, '7.3', '<')) {
        deactivate_plugins(plugin_basename(__FILE__));
        wp_die(esc_html__('TalkGenAI requires PHP 7.3 or higher.', 'talkgenai'));
    }
    
    // Check WordPress version
    if (version_compare(get_bloginfo('version'), '5.0', '<')) {
        deactivate_plugins(plugin_basename(__FILE__));
        wp_die(esc_html__('TalkGenAI requires WordPress 5.0 or higher.', 'talkgenai'));
    }
    
    // Ensure database class is loaded
    if (!class_exists('TalkGenAI_Database')) {
        require_once plugin_dir_path(__FILE__) . 'includes/class-talkgenai-database.php';
    }
    
    // Create database tables - CRITICAL: Plugin cannot work without these
    try {
        $database = new TalkGenAI_Database();
        $database->create_tables();
        
        // Verify tables were created successfully
        global $wpdb;
        $table_name = esc_sql($wpdb->prefix . 'talkgenai_apps');
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct query needed to verify table creation during activation
        $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) == $table_name;
        
        if (!$table_exists) {
            throw new Exception(__('Failed to create required database table: wp_talkgenai_apps', 'talkgenai'));
        }
        
        // Set default options
        add_option('talkgenai_server_mode', 'local');
        add_option('talkgenai_local_server_url', 'http://localhost:8000');
        add_option('talkgenai_api_key', '');
        
        // Flush rewrite rules
        flush_rewrite_rules();
        
        // Debug logging removed for WordPress.org submission
        // if (defined('WP_DEBUG') && WP_DEBUG) {
        //     error_log('TalkGenAI: Plugin activated successfully via standalone function');
        // }
        
    } catch (Exception $e) {
        // Database creation failed - deactivate plugin and show error
        deactivate_plugins(plugin_basename(__FILE__));
        wp_die(
            '<h1>' . esc_html__('TalkGenAI Activation Failed', 'talkgenai') . '</h1>' .
            '<p><strong>' . esc_html__('Database Error:', 'talkgenai') . '</strong> ' . esc_html($e->getMessage()) . '</p>' .
            '<p>' . esc_html__('The plugin could not create its required database tables. Please contact your hosting provider or system administrator.', 'talkgenai') . '</p>' .
            '<p><a href="' . esc_url(admin_url('plugins.php')) . '">' . esc_html__('Return to Plugins', 'talkgenai') . '</a></p>',
            esc_html__('Plugin Activation Failed', 'talkgenai'),
            array('response' => 500)
        );
    }
}

/**
 * Plugin deactivation function
 */
function talkgenai_deactivate() {
    // Flush rewrite rules
    flush_rewrite_rules();
    
    // Debug logging removed for WordPress.org submission
    // if (defined('WP_DEBUG') && WP_DEBUG) {
    //     error_log('TalkGenAI: Plugin deactivated via standalone function');
    // }
}

// Register activation and deactivation hooks
register_activation_hook(__FILE__, 'talkgenai_activate');
register_deactivation_hook(__FILE__, 'talkgenai_deactivate');
