<?php

/**
 * Aysa Banned Keywords Manager
 *
 * Handles banned keywords functionality including creating table,
 * banning/unbanning keywords, and checking associations.
 *
 * @since      1.0.0
 * @package    Aysa
 * @subpackage Aysa/includes
 */

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

/**
 * The banned keywords manager class.
 *
 * @since      1.0.0
 * @package    Aysa
 * @subpackage Aysa/includes
 */
class Aysa_Banned_Keywords_Manager {

    /**
     * The table name for banned keywords
     *
     * @since    1.0.0
     * @access   private
     * @var      string    $table_name    The banned keywords table name
     */
    private $table_name;

    /**
     * Initialize the class
     *
     * @since    1.0.0
     */
    public function __construct() {
        global $wpdb;
        $this->table_name = esc_sql($wpdb->prefix . 'aysa_banned_keywords');
        
        // Create table immediately during construction
        $this->maybe_create_table();
        
        // Add AJAX handlers
        add_action('wp_ajax_aysa_ban_keyword', array($this, 'ajax_ban_keyword'));
        add_action('wp_ajax_aysa_unban_keyword', array($this, 'ajax_unban_keyword'));
        add_action('wp_ajax_aysa_get_banned_keywords', array($this, 'ajax_get_banned_keywords'));
        add_action('wp_ajax_aysa_check_keyword_association', array($this, 'ajax_check_keyword_association'));
    }

    /**
     * Create table if it doesn't exist
     *
     * @since    1.0.0
     */
    public function maybe_create_table() {
        $table_version = get_option('aysa_banned_keywords_table_version', '0.0.0');
        
        if (version_compare($table_version, '1.0.0', '<')) {
            $this->create_table();
        }
    }

    /**
     * Create the banned keywords table
     *
     * @since    1.0.0
     */
    public function create_table() {
        global $wpdb;
        
        try {
            $charset_collate = $this->get_safe_charset_collate();
            
            $sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
                id bigint(20) NOT NULL AUTO_INCREMENT,
                keyword varchar(255) NOT NULL,
                banned_by bigint(20) NOT NULL,
                banned_reason text DEFAULT NULL,
                project_id bigint(20) DEFAULT 0,
                created_at datetime DEFAULT CURRENT_TIMESTAMP,
                updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                PRIMARY KEY (id),
                UNIQUE KEY unique_keyword_project (keyword, project_id),
                KEY keyword_lookup (keyword),
                KEY banned_by (banned_by),
                KEY project_id (project_id),
                KEY created_at (created_at)
            ) $charset_collate;";
            
            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
            
            aysa_debug_log('[AYSA Banned Keywords] Creating table with SQL: ' . $sql);
            $result = dbDelta($sql);
            
            // Check if table was actually created
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
            $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $this->table_name));
            
            if ($table_exists) {
                aysa_debug_log('[AYSA Banned Keywords] Table created/verified successfully');
                update_option('aysa_banned_keywords_table_version', '1.0.0');
                return true;
            } else {
                aysa_debug_log('[AYSA Banned Keywords] Table creation failed - table does not exist after dbDelta');
                if ($wpdb->last_error) {
                    aysa_debug_log('[AYSA Banned Keywords] MySQL Error: ' . $wpdb->last_error);
                }
                return false;
            }
            
        } catch (Exception $e) {
            aysa_debug_log('[AYSA Banned Keywords] Exception during table creation: ' . $e->getMessage());
            return false;
        } catch (Error $e) {
            aysa_debug_log('[AYSA Banned Keywords] Fatal error during table creation: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Get safe charset collate for table creation
     *
     * @since    1.0.0
     */
    private function get_safe_charset_collate() {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();
        
        // Fix charset issue for certain hosting environments
        if (strpos($charset_collate, 'UTF-8') !== false) {
            $charset_collate = str_replace('UTF-8', 'utf8mb4', $charset_collate);
        }
        
        // Fallback to safe default if charset_collate is empty or invalid
        if (empty($charset_collate) || strpos($charset_collate, 'UTF-8') !== false) {
            $charset_collate = 'DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci';
        }
        
        return $charset_collate;
    }

    /**
     * Check if a keyword is associated with any post/page
     *
     * @since    1.0.0
     * @param    string    $keyword    The keyword to check
     * @param    int       $project_id The project ID
     * @return   boolean   True if keyword is associated, false otherwise
     */
    public function is_keyword_associated($keyword, $project_id = 0) {
        global $wpdb;
        
        try {
            aysa_debug_log('[AYSA Banned Keywords] Checking if keyword is associated: ' . $keyword);
            
            // Method 1: Check via API if auth manager is available
            if (class_exists('Aysa_Auth_Manager')) {
                try {
                    $auth_manager = new Aysa_Auth_Manager();
                    
                    if ($auth_manager->is_authenticated()) {
                        $api_response = $auth_manager->make_authenticated_request(
                            'associations/get-all',
                            'GET'
                        );
                        
                        if ($api_response && isset($api_response['data'])) {
                            $associations = $api_response['data'];
                            
                            foreach ($associations as $association) {
                                if (isset($association['keyword']) && 
                                    strtolower(trim($association['keyword'])) === strtolower(trim($keyword))) {
                                    aysa_debug_log('[AYSA Banned Keywords] Keyword found in API associations');
                                    return true;
                                }
                            }
                        }
                    }
                } catch (Exception $e) {
                    aysa_debug_log('[AYSA Banned Keywords] API check failed, falling back to local check: ' . $e->getMessage());
                }
            }
            
            // Method 2: Check local WordPress meta tables for keyword associations
            $keyword_lower = strtolower(trim($keyword));
            
            // Check post meta for keyword associations
            $keyword_meta_like = '%' . $wpdb->esc_like('keyword') . '%';
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
            $post_associations = $wpdb->get_results($wpdb->prepare(
                "SELECT post_id FROM {$wpdb->postmeta} 
                 WHERE meta_key LIKE %s 
                 AND LOWER(meta_value) = %s 
                 LIMIT 1",
                $keyword_meta_like,
                $keyword_lower
            ));
            
            if (!empty($post_associations)) {
                aysa_debug_log('[AYSA Banned Keywords] Keyword found in post meta associations');
                return true;
            }
            
            // Check term meta for keyword associations
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
            $term_associations = $wpdb->get_results($wpdb->prepare(
                "SELECT term_id FROM {$wpdb->termmeta} 
                 WHERE meta_key LIKE %s 
                 AND LOWER(meta_value) = %s 
                 LIMIT 1",
                $keyword_meta_like,
                $keyword_lower
            ));
            
            if (!empty($term_associations)) {
                aysa_debug_log('[AYSA Banned Keywords] Keyword found in term meta associations');
                return true;
            }
            
            // Method 3: Check if keyword appears in any title or content (as a last resort)
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
            $content_check = $wpdb->get_results($wpdb->prepare(
                "SELECT ID FROM {$wpdb->posts} 
                 WHERE post_status = 'publish' 
                 AND (LOWER(post_title) LIKE %s OR LOWER(post_content) LIKE %s)
                 LIMIT 1",
                '%' . $keyword_lower . '%',
                '%' . $keyword_lower . '%'
            ));
            
            if (!empty($content_check)) {
                aysa_debug_log('[AYSA Banned Keywords] Keyword found in post content/title');
                return true;
            }
            
            aysa_debug_log('[AYSA Banned Keywords] Keyword not found in any associations');
            return false;
            
        } catch (Exception $e) {
            aysa_debug_log('[AYSA Banned Keywords] Error checking associations: ' . $e->getMessage());
            return false;
        } catch (Error $e) {
            aysa_debug_log('[AYSA Banned Keywords] Fatal error checking associations: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Ban a keyword
     *
     * @since    1.0.0
     * @param    string    $keyword    The keyword to ban
     * @param    int       $project_id The project ID
     * @param    string    $reason     Optional reason for banning
     * @return   array     Result with success status and message
     */
    public function ban_keyword($keyword, $project_id = 0, $reason = '') {
        global $wpdb;
        
        // Sanitize inputs
        $keyword = sanitize_text_field($keyword);
        $project_id = intval($project_id);
        $reason = sanitize_textarea_field($reason);
        
        // Check if keyword is already banned
        if ($this->is_keyword_banned($keyword, $project_id)) {
            return array(
                'success' => false,
                'message' => 'Keyword is already banned'
            );
        }
        
        // Temporarily disable association checking to avoid critical errors
        // TODO: Re-enable once association checking is stable
        // Note: Users should manually disassociate keywords before deleting
        
        // Insert banned keyword
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        $result = $wpdb->insert(
            $this->table_name,
            array(
                'keyword' => $keyword,
                'banned_by' => get_current_user_id(),
                'banned_reason' => $reason,
                'project_id' => $project_id
            ),
            array('%s', '%d', '%s', '%d')
        );
        
        if ($result) {
            return array(
                'success' => true,
                'message' => 'Keyword deleted successfully'
            );
        } else {
            return array(
                'success' => false,
                'message' => 'Failed to delete keyword: ' . $wpdb->last_error
            );
        }
    }

    /**
     * Count associations for a keyword
     *
     * @since    1.0.0
     * @param    string    $keyword    The keyword to count associations for
     * @param    int       $project_id The project ID
     * @return   int       Number of associations found
     */
    public function count_keyword_associations($keyword, $project_id = 0) {
        try {
            aysa_debug_log('[AYSA Banned Keywords] Counting associations for keyword: ' . $keyword . ' with project_id: ' . $project_id);
            
            // Check via API if auth manager is available
            if (class_exists('Aysa_Auth_Manager')) {
                try {
                    $auth_manager = new Aysa_Auth_Manager();
                    
                    if ($auth_manager->is_authenticated()) {
                        // Get all associations for this project
                        $get_url = 'associations/get-all';
                        if ($project_id > 0) {
                            $get_url .= '?projectId=' . $project_id;
                        }
                        
                        $api_response = $auth_manager->make_authenticated_request(
                            $get_url,
                            'GET'
                        );
                        
                        if ($api_response && isset($api_response['data'])) {
                            $associations = $api_response['data'];
                            $keyword_lower = strtolower(trim($keyword));
                            
                            // Count associations for this keyword
                            $count = 0;
                            foreach ($associations as $association) {
                                if (isset($association['keyword']) && 
                                    strtolower(trim($association['keyword'])) === $keyword_lower) {
                                    $count++;
                                    aysa_debug_log('[AYSA Banned Keywords] Found association ID: ' . ($association['id'] ?? 'unknown') . ' for keyword: ' . $keyword);
                                }
                            }
                            
                            aysa_debug_log('[AYSA Banned Keywords] Found ' . $count . ' associations for keyword: ' . $keyword);
                            return $count;
                        } else {
                            aysa_debug_log('[AYSA Banned Keywords] No associations data received from API');
                            return 0;
                        }
                    } else {
                        aysa_debug_log('[AYSA Banned Keywords] Auth manager is not authenticated');
                        return 0;
                    }
                } catch (Exception $e) {
                    aysa_debug_log('[AYSA Banned Keywords] API association count failed: ' . $e->getMessage());
                    return 0;
                }
            } else {
                aysa_debug_log('[AYSA Banned Keywords] Auth manager class not available');
                return 0;
            }
        } catch (Exception $e) {
            aysa_debug_log('[AYSA Banned Keywords] Error counting associations: ' . $e->getMessage());
            return 0;
        }
    }

    /**
     * Remove all associations for a keyword
     *
     * @since    1.0.0
     * @param    string    $keyword    The keyword to remove associations for
     * @param    int       $project_id The project ID
     * @return   boolean   True if successful, false otherwise
     */
    public function remove_keyword_associations($keyword, $project_id = 0) {
        global $wpdb;
        
        try {
            aysa_debug_log('[AYSA Banned Keywords] Removing associations for keyword: ' . $keyword . ' with project_id: ' . $project_id);
            
            $associations_removed = 0;
            
            // Method 1: Remove via API if auth manager is available
            if (class_exists('Aysa_Auth_Manager')) {
                try {
                    $auth_manager = new Aysa_Auth_Manager();
                    
                    if ($auth_manager->is_authenticated()) {
                        // Get all associations for this project
                        $get_url = 'associations/get-all';
                        if ($project_id > 0) {
                            $get_url .= '?projectId=' . $project_id;
                        }
                        
                        $api_response = $auth_manager->make_authenticated_request(
                            $get_url,
                            'GET'
                        );
                        
                        if ($api_response && isset($api_response['data'])) {
                            $associations = $api_response['data'];
                            $keyword_lower = strtolower(trim($keyword));
                            
                            aysa_debug_log('[AYSA Banned Keywords] Found ' . count($associations) . ' total associations to check');
                            
                            // Find associations for this keyword
                            $keyword_associations = array_filter($associations, function($association) use ($keyword_lower) {
                                return isset($association['keyword']) && 
                                       strtolower(trim($association['keyword'])) === $keyword_lower;
                            });
                            
                            aysa_debug_log('[AYSA Banned Keywords] Found ' . count($keyword_associations) . ' associations for keyword: ' . $keyword);
                            
                            // Delete each association via API
                            foreach ($keyword_associations as $association) {
                                if (isset($association['id'])) {
                                    try {
                                        $delete_url = 'Association/' . $association['id'];
                                        if ($project_id > 0) {
                                            $delete_url .= '?projectId=' . $project_id;
                                        }
                                        
                                        $delete_response = $auth_manager->make_authenticated_request(
                                            $delete_url,
                                            'DELETE'
                                        );
                                        
                                        if ($delete_response !== false) {
                                            $associations_removed++;
                                            aysa_debug_log('[AYSA Banned Keywords] Successfully deleted association ID: ' . $association['id']);
                                        } else {
                                            aysa_debug_log('[AYSA Banned Keywords] Failed to delete association ID: ' . $association['id'] . ' - API returned false');
                                        }
                                    } catch (Exception $e) {
                                        aysa_debug_log('[AYSA Banned Keywords] Failed to delete association ' . $association['id'] . ': ' . $e->getMessage());
                                    }
                                }
                            }
                        } else {
                            aysa_debug_log('[AYSA Banned Keywords] No associations data received from API');
                        }
                    } else {
                        aysa_debug_log('[AYSA Banned Keywords] Auth manager is not authenticated');
                    }
                } catch (Exception $e) {
                    aysa_debug_log('[AYSA Banned Keywords] API association removal failed: ' . $e->getMessage());
                }
            } else {
                aysa_debug_log('[AYSA Banned Keywords] Auth manager class not available');
            }
            
            aysa_debug_log('[AYSA Banned Keywords] Association removal completed. Removed ' . $associations_removed . ' associations for keyword: ' . $keyword);
            return true;
            
        } catch (Exception $e) {
            aysa_debug_log('[AYSA Banned Keywords] Error removing associations: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Unban a keyword
     *
     * @since    1.0.0
     * @param    string    $keyword    The keyword to unban
     * @param    int       $project_id The project ID
     * @return   array     Result with success status and message
     */
    public function unban_keyword($keyword, $project_id = 0) {
        global $wpdb;
        
        // Sanitize inputs
        $keyword = sanitize_text_field($keyword);
        $project_id = intval($project_id);
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        $result = $wpdb->delete(
            $this->table_name,
            array(
                'keyword' => $keyword,
                'project_id' => $project_id
            ),
            array('%s', '%d')
        );
        
        if ($result) {
            return array(
                'success' => true,
                'message' => 'Keyword unbanned successfully'
            );
        } else {
            return array(
                'success' => false,
                'message' => 'Failed to unban keyword or keyword was not banned'
            );
        }
    }

    /**
     * Check if a keyword is banned
     *
     * @since    1.0.0
     * @param    string    $keyword    The keyword to check
     * @param    int       $project_id The project ID
     * @return   boolean   True if keyword is banned, false otherwise
     */
    public function is_keyword_banned($keyword, $project_id = 0) {
        global $wpdb;
        
        $keyword = sanitize_text_field($keyword);
        $project_id = intval($project_id);
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        $banned = $wpdb->get_var($wpdb->prepare(
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Internal AYSA banned keywords table name is derived from the WordPress prefix and a fixed suffix.
            "SELECT id FROM {$this->table_name} WHERE keyword = %s AND project_id = %d",
            $keyword,
            $project_id
        ));
        
        return !empty($banned);
    }

    /**
     * Get all banned keywords
     *
     * @since    1.0.0
     * @param    int       $project_id The project ID
     * @param    int       $limit      Limit number of results
     * @param    int       $offset     Offset for pagination
     * @return   array     Array of banned keywords
     */
    public function get_banned_keywords($project_id = 0, $limit = 50, $offset = 0) {
        global $wpdb;
        
        $project_id = intval($project_id);
        $limit = intval($limit);
        $offset = intval($offset);
        
        $sql = $wpdb->prepare(
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reviewed release SQL: interpolation is limited to escaped or allowlisted plugin-owned table identifiers and generated placeholder lists; all request-derived values are passed to prepare. Reviewed release SQL: interpolation is limited to escaped or allowlisted plugin-owned table identifiers and generated placeholder lists; all request-derived values are passed to prepare.
            "SELECT bk.*, u.display_name as banned_by_name 
" .
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reviewed release SQL: the interpolated identifier is an escaped or allowlisted plugin-owned table name; request-derived values remain prepared.
            "             FROM {$this->table_name} bk 
             LEFT JOIN {$wpdb->users} u ON bk.banned_by = u.ID 
             WHERE bk.project_id = %d 
             ORDER BY bk.created_at DESC 
             LIMIT %d OFFSET %d",
            $project_id,
            $limit,
            $offset
        );
        
        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query: table identifiers and structure are internal, and request-derived values are prepared before execution. Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        return $wpdb->get_results($sql);
    }

    /**
     * Get banned keywords count
     *
     * @since    1.0.0
     * @param    int       $project_id The project ID
     * @return   int       Count of banned keywords
     */
    public function get_banned_keywords_count($project_id = 0) {
        global $wpdb;
        
        $project_id = intval($project_id);
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        $count = $wpdb->get_var($wpdb->prepare(
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reviewed release SQL: interpolation is limited to escaped or allowlisted plugin-owned table identifiers and generated placeholder lists; all request-derived values are passed to prepare.
            "SELECT COUNT(*) FROM {$this->table_name} WHERE project_id = %d",
            $project_id
        ));
        
        return $count;
    }

    /**
     * Filter keywords to exclude banned ones
     *
     * @since    1.0.0
     * @param    array     $keywords   Array of keywords to filter
     * @param    int       $project_id The project ID
     * @return   array     Filtered keywords array
     */
    public function filter_banned_keywords($keywords, $project_id = 0) {
        if (empty($keywords)) {
            return $keywords;
        }
        
        global $wpdb;
        $project_id = intval($project_id);
        
        // Get all banned keywords for this project
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        $banned_keywords = $wpdb->get_col($wpdb->prepare(
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reviewed release SQL: interpolation is limited to escaped or allowlisted plugin-owned table identifiers and generated placeholder lists; all request-derived values are passed to prepare.
            "SELECT keyword FROM {$this->table_name} WHERE project_id = %d",
            $project_id
        ));
        
        if (empty($banned_keywords)) {
            return $keywords;
        }
        
        // Convert to lowercase for comparison
        $banned_keywords_lower = array_map('strtolower', $banned_keywords);
        
        // Filter out banned keywords
        return array_filter($keywords, function($keyword_data) use ($banned_keywords_lower) {
            if (is_array($keyword_data) && isset($keyword_data['keyword'])) {
                $keyword = strtolower(trim($keyword_data['keyword']));
            } else if (is_string($keyword_data)) {
                $keyword = strtolower(trim($keyword_data));
            } else {
                return true; // Keep if we can't determine the keyword
            }
            
            return !in_array($keyword, $banned_keywords_lower);
        });
    }

    /**
     * Get a global instance of the banned keywords manager
     *
     * @since    1.0.0
     * @return   Aysa_Banned_Keywords_Manager
     */
    public static function get_instance() {
        static $instance = null;
        if ($instance === null) {
            $instance = new self();
        }
        return $instance;
    }

    /**
     * AJAX handler to ban a keyword
     *
     * @since    1.0.0
     */
    public function ajax_ban_keyword() {
        try {
            aysa_debug_log('[AYSA Banned Keywords] ajax_ban_keyword called');
            
            // Check nonce
            if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'aysa_banned_keywords_nonce')) {
                aysa_debug_log('[AYSA Banned Keywords] Security check failed - invalid nonce');
                wp_send_json_error('Security check failed');
                return;
            }
            
            // Check permissions
            if (!current_user_can('manage_options')) {
                aysa_debug_log('[AYSA Banned Keywords] Insufficient permissions for user: ' . get_current_user_id());
                wp_send_json_error('Insufficient permissions');
                return;
            }
            
            $keyword = isset($_POST['keyword']) ? sanitize_text_field(wp_unslash($_POST['keyword'])) : '';
            $project_id = isset($_POST['project_id']) ? intval(wp_unslash($_POST['project_id'])) : 0;
            $reason = isset($_POST['reason']) ? sanitize_textarea_field(wp_unslash($_POST['reason'])) : '';
            
            aysa_debug_log('[AYSA Banned Keywords] Attempting to ban keyword: ' . $keyword);
            
            if (empty($keyword)) {
                aysa_debug_log('[AYSA Banned Keywords] Keyword is empty');
                wp_send_json_error('Keyword is required');
                return;
            }
            
            $result = $this->ban_keyword($keyword, $project_id, $reason);
            
            aysa_debug_log('[AYSA Banned Keywords] Ban result: ' . json_encode($result));
            
            if ($result['success']) {
                wp_send_json_success($result['message']);
            } else {
                wp_send_json_error($result['message']);
            }
            
        } catch (Exception $e) {
            aysa_debug_log('[AYSA Banned Keywords] Exception in ajax_ban_keyword: ' . $e->getMessage());
            wp_send_json_error('Internal error: ' . $e->getMessage());
        }
    }

    /**
     * AJAX handler to unban a keyword
     *
     * @since    1.0.0
     */
    public function ajax_unban_keyword() {
        // Check nonce
        if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'] ?? '')), 'aysa_banned_keywords_nonce')) {
            wp_die('Security check failed');
        }
        
        // Check permissions
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions');
        }
        
        $keyword = isset($_POST['keyword']) ? sanitize_text_field(wp_unslash($_POST['keyword'])) : '';
        $project_id = isset($_POST['project_id']) ? intval(wp_unslash($_POST['project_id'])) : 0;
        
        if (empty($keyword)) {
            wp_send_json_error('Keyword is required');
        }
        
        $result = $this->unban_keyword($keyword, $project_id);
        
        if ($result['success']) {
            wp_send_json_success($result['message']);
        } else {
            wp_send_json_error($result['message']);
        }
    }

    /**
     * AJAX handler to get banned keywords
     *
     * @since    1.0.0
     */
    public function ajax_get_banned_keywords() {
        try {
            aysa_debug_log('[AYSA Banned Keywords] ajax_get_banned_keywords called');
            
            // Check nonce
            if (!isset($_REQUEST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['nonce'])), 'aysa_banned_keywords_nonce')) {
                aysa_debug_log('[AYSA Banned Keywords] Get keywords: Security check failed - invalid nonce');
                wp_send_json_error('Security check failed');
                return;
            }
            
            // Check permissions
            if (!current_user_can('manage_options')) {
                aysa_debug_log('[AYSA Banned Keywords] Get keywords: Insufficient permissions for user: ' . get_current_user_id());
                wp_send_json_error('Insufficient permissions');
                return;
            }
            
            $project_id = isset($_REQUEST['project_id']) ? intval(wp_unslash($_REQUEST['project_id'])) : 0;
            $limit = isset($_REQUEST['limit']) ? intval(wp_unslash($_REQUEST['limit'])) : 50;
            $offset = isset($_REQUEST['offset']) ? intval(wp_unslash($_REQUEST['offset'])) : 0;
            
            aysa_debug_log('[AYSA Banned Keywords] Getting banned keywords for project: ' . $project_id);
            
            $banned_keywords = $this->get_banned_keywords($project_id, $limit, $offset);
            $total_count = $this->get_banned_keywords_count($project_id);
            
            aysa_debug_log('[AYSA Banned Keywords] Found ' . count($banned_keywords) . ' keywords, total: ' . $total_count);
            
            wp_send_json_success(array(
                'keywords' => $banned_keywords,
                'total' => $total_count,
                'limit' => $limit,
                'offset' => $offset
            ));
            
        } catch (Exception $e) {
            aysa_debug_log('[AYSA Banned Keywords] Exception in ajax_get_banned_keywords: ' . $e->getMessage());
            wp_send_json_error('Internal error: ' . $e->getMessage());
        }
    }

    /**
     * AJAX handler to check if keyword is associated
     *
     * @since    1.0.0
     */
    public function ajax_check_keyword_association() {
        // Check nonce
        if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['nonce'] ?? '')), 'aysa_banned_keywords_nonce')) {
            wp_die('Security check failed');
        }
        
        // Check permissions
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions');
        }
        
        $keyword = isset($_REQUEST['keyword']) ? sanitize_text_field(wp_unslash($_REQUEST['keyword'])) : '';
        $project_id = isset($_REQUEST['project_id']) ? intval(wp_unslash($_REQUEST['project_id'])) : 0;
        
        if (empty($keyword)) {
            wp_send_json_error('Keyword is required');
        }
        
        $is_associated = $this->is_keyword_associated($keyword, $project_id);
        
        wp_send_json_success(array(
            'is_associated' => $is_associated,
            'keyword' => $keyword
        ));
    }
}
