<?php
/*
Plugin Name: RANK AI by Morningscore
Description: Automatically fix health problems found in Morningscore via RANK AI
Version: 1.0.1
Author: Morningscore
*/


/* ==== documentation ====

class-rank-admin.php: all the admin functionality
class-rank-ajax.php: all the ajax functionality for processing and instant updates and logging
class-rank-processor.php: Uses Action Scheduler to process the batch data in chunks and save new data to db
api-caller.php: all the api functionality for calling the RANK AI API and get health fixes. Called by Action Scheduler.
class-rank-frontend-filters.php: Fetching data from db and using hooks/filters to modify frontend 

*/

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// Define plugin constants
define( 'RANK_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'RANK_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'RANK_DB_VERSION', '1.8' ); // Database version - incremented for Rank Writer table
define( 'RANK_TABLE_NAME', 'rank_seo_overrides' ); // Table name without prefix
define( 'RANK_EXACT_ALT_MATCHING', false ); // Set to true for exact alt tag matching (slower but more precise)

// Initialize the Plugin Update Checker
require_once RANK_PLUGIN_DIR . 'plugin-update-checker/plugin-update-checker.php';
$rankUpdateChecker = YahnisElsts\PluginUpdateChecker\v5p5\PucFactory::buildUpdateChecker(
    'https://morningscore.io/dl/rank/wp-rank-ai-update-plugin.json',
    __FILE__,
    'rank-ai-by-morningscore'
);

// Include Action Scheduler library globally
require_once RANK_PLUGIN_DIR . 'lib/action-scheduler/action-scheduler.php';

// Include core plugin files that only define classes/functions but don't execute actions or add hooks yet.
require_once RANK_PLUGIN_DIR . 'includes/config.php';
require_once RANK_PLUGIN_DIR . 'includes/api-caller.php';
require_once RANK_PLUGIN_DIR . 'includes/class-rank-admin.php';
require_once RANK_PLUGIN_DIR . 'includes/class-rank-ajax.php';
require_once RANK_PLUGIN_DIR . 'includes/class-rank-already-fixed-checker.php';
require_once RANK_PLUGIN_DIR . 'includes/class-rank-processor.php';
require_once RANK_PLUGIN_DIR . 'includes/class-rank-frontend-filters.php';
require_once RANK_PLUGIN_DIR . 'includes/class-rank-delete-handler.php';
require_once RANK_PLUGIN_DIR . 'includes/class-rank-url-list.php';
require_once RANK_PLUGIN_DIR . 'includes/rank-writer/class-rank-writer.php';

// Register activation/deactivation hooks - these are fine here
register_activation_hook( __FILE__, 'rank_activate_plugin' );
register_deactivation_hook( __FILE__, 'rank_deactivate_plugin' );

/**
 * Plugin activation.
 */
function rank_activate_plugin() {
    global $wpdb;
    $table_name = $wpdb->prefix . RANK_TABLE_NAME;
    $charset_collate = $wpdb->get_charset_collate();

    // Check if the table already exists to decide if we need to update the schema
    // $table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) ) === $table_name;

    // SQL to create/update the table
    // IMPORTANT: dbDelta is sensitive to formatting.
    // Each field should be on its own line.
    // There should be two spaces between PRIMARY KEY and the definition of the key.
    // There should be one space between KEY/UNIQUE KEY and the key name.
    $sql = "CREATE TABLE $table_name (
        override_id mediumint(9) NOT NULL AUTO_INCREMENT,
        post_id bigint(20) UNSIGNED NOT NULL,
        object_id BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
        override_type varchar(50) NOT NULL,
        issue_type varchar(50) DEFAULT NULL,
        override_value longtext NOT NULL,
        original_page_url text DEFAULT NULL,
        image_url text DEFAULT NULL,
        created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
        updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        PRIMARY KEY  (override_id),
        UNIQUE KEY unique_override (post_id, object_id, override_type, original_page_url(255)),
        KEY idx_post_type (post_id, override_type),
        KEY idx_object_type (object_id, override_type)
    ) $charset_collate;";

    // Include upgrade script for dbDelta()
    require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
    dbDelta( $sql );

    // Store the version
    update_option('rank_db_version', RANK_DB_VERSION, false);
    
    // Fix autoload settings for existing options
    rank_fix_autoload_settings();
    
    // Clear any remaining permission check cache
    delete_transient('rank_db_permissions_check');
    
    // Create Rank Writer uploads table
    require_once RANK_PLUGIN_DIR . 'includes/rank-writer/class-rank-writer-db.php';
    Rank_Writer_DB::create_table();
}

/**
 * Plugin deactivation.
 */
function rank_deactivate_plugin() {
    // Clear scheduled actions
    if ( function_exists( 'as_unschedule_all_actions' ) ) {
        as_unschedule_all_actions( 'rank_process_queue_item' );
    }
}

/**
 * Enqueue admin scripts with proper dependencies
 */
function rank_enqueue_admin_scripts() {
    // Only load on admin pages
    if (!is_admin()) {
        return;
    }
    
    // Get the current screen to check if we're on our plugin page
    $screen = get_current_screen();
    if ( ! $screen || 'toplevel_page_rank-admin' !== $screen->id ) {
        return;
    }
    
    // Helper function to get file modification time for cache busting
    function get_file_version($file_path) {
        $full_path = RANK_PLUGIN_DIR . $file_path;
        return file_exists($full_path) ? filemtime($full_path) : '1.0';
    }
    
    // Enqueue jQuery
    wp_enqueue_script('jquery');
    
    // Enqueue modular scripts in proper order with dynamic versioning
    wp_enqueue_script(
        'rank-helpers',
        RANK_PLUGIN_URL . 'admin/js/modules/helpers.js',
        array('jquery'),
        get_file_version('admin/js/modules/helpers.js'),
        true
    );
    
    wp_enqueue_script(
        'rank-health-issues',
        RANK_PLUGIN_URL . 'admin/js/modules/sequential-health-issues.js',
        array('jquery', 'rank-helpers'),
        get_file_version('admin/js/modules/sequential-health-issues.js'),
        true
    );
    
    wp_enqueue_script(
        'rank-approval',
        RANK_PLUGIN_URL . 'admin/js/modules/approval.js',
        array('jquery', 'rank-helpers'),
        get_file_version('admin/js/modules/approval.js'),
        true
    );
    
    wp_enqueue_script(
        'rank-processing',
        RANK_PLUGIN_URL . 'admin/js/modules/processing.js',
        array('jquery', 'rank-helpers', 'rank-approval'),
        get_file_version('admin/js/modules/processing.js'),
        true
    );
    
    // Enqueue the fixes tab script
    wp_enqueue_script(
        'rank-admin-fixes',
        RANK_PLUGIN_URL . 'admin/js/admin-fixes.js',
        array('jquery', 'rank-helpers'),
        get_file_version('admin/js/admin-fixes.js'),
        true
    );
    
    // Main admin script (loads last)
    wp_enqueue_script(
        'rank-admin',
        RANK_PLUGIN_URL . 'admin/js/admin.js',
        array('jquery', 'rank-helpers', 'rank-health-issues', 'rank-approval', 'rank-processing', 'rank-admin-fixes'),
        get_file_version('admin/js/admin.js'),
        true
    );
    
    // Rank Writer tab script
    wp_enqueue_script(
        'rank-writer',
        RANK_PLUGIN_URL . 'admin/js/modules/rank-writer.js',
        array('jquery', 'rank-helpers'),
        get_file_version('admin/js/modules/rank-writer.js'),
        true
    );
    
    // Rank Writer styles
    wp_enqueue_style(
        'rank-writer-css',
        RANK_PLUGIN_URL . 'admin/css/rank-writer.css',
        array(),
        get_file_version('admin/css/rank-writer.css')
    );
    
    // Localize script with data needed for AJAX and UI
    $translation_array = array(
        'ajax_url' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('rank_ajax_nonce'),
        'plugin_url' => RANK_PLUGIN_URL, // Add plugin URL for dynamic asset loading
        'status_preparing' => __('Preparing health issues...', 'rank-seo'),
        'status_reviewing' => __('Ready for review. Decide for each item.', 'rank-seo'),
        'status_scheduling' => __('Scheduling tasks for processing...', 'rank-seo'),
        'status_prepared' => __('Health issues prepared. Ready to start fixing.', 'rank-seo'),
        'status_complete' => __('Processing Complete!', 'rank-seo'),
        'prepare_urls_text' => __('Prepare URLs', 'rank-seo'),
        'start_fixing_text' => __('Start Fixing', 'rank-seo'),
        'text_decide_label' => __('Review', 'rank-seo'),
        'error_scheduling' => __('Error scheduling tasks.', 'rank-seo'),
        'error_no_batch_id' => __('No batch ID found. Please try preparing again.', 'rank-seo'),
        'delete_success_message' => __('All RANK AI data deleted successfully.', 'rank-seo'),
        'delete_error_message' => __('Error deleting data.', 'rank-seo'),
        'confirm_delete_text' => __('DELETE', 'rank-seo'),
        'confirm_cancel_text' => __('Are you sure you want to cancel? This will reset all processing. All processed fixes are saved ✅.', 'rank-seo'),
        'force_reload_on_cancel' => apply_filters('rank_force_reload_on_cancel', '0'), // '0' = disabled, '1' = enabled
        // For admin-fixes.js pagination
        'text_page' => __('Page', 'rank-seo'),
        'text_of' => __('of', 'rank-seo'),
        'text_items' => __('items', 'rank-seo'),
        'text_prev' => __('Previous', 'rank-seo'),
        'text_next' => __('Next', 'rank-seo'),
        'issue_type_labels' => array(
            'missing_alt_tags' => __('Image missing alt tag', 'rank-seo'),
            'missing_meta_description' => __('Missing meta description', 'rank-seo'),
            // Add other issue types here
        )
    );
    
    // Localize to the main admin script. Modules can access it as it's global.
    wp_localize_script('rank-helpers', 'rank_ajax_obj', $translation_array);

    // Localize data specifically for the health issues module
    $health_check_categories = function_exists('rank_get_health_check_categories') ? rank_get_health_check_categories() : array();
    $localized_data_for_health_issues = array(
        'ajax_url' => admin_url('admin-ajax.php'),
        'nonce'    => wp_create_nonce('rank_ajax_nonce'), // Using the same nonce as rank_ajax_obj for consistency
        'healthCheckCategories' => $health_check_categories,
        'text_credits_exhausted' => __('Your AI credits have run out.', 'rank-seo'),
        'text_no_issues_found' => __('No health issues found that require fixing. Good job!', 'rank-seo'),
        'text_no_issues_credits_exhausted' => __('No health issues found that require fixing, and AI credits have run out.', 'rank-seo'),
        'text_error_loading_issues' => __('Error loading health issues:', 'rank-seo'),
        'text_ajax_error_loading_issues' => __('AJAX Error loading health issues:', 'rank-seo'),
        'text_config_missing' => __('Error: Health check categories configuration is missing.', 'rank-seo'),
        'text_all_good' => __('All good ✅', 'rank-seo'),
        'text_fix_issues' => __('Fix Issues', 'rank-seo'),
        'status_preparing' => __('Preparing health issues...', 'rank-seo'),
        'tooltip_already_fixed' => __('Try to do a full Health scan. Expect ≈10% fixes to not be detected. WordPress is very complex. Nothing breaks if it does not work. Good luck, captain! 🧑‍🚀👍️', 'rank-seo')
    );
    wp_localize_script('rank-health-issues', 'rankLocalizedData', $localized_data_for_health_issues);
}
add_action('admin_enqueue_scripts', 'rank_enqueue_admin_scripts');

/**
 * Initialize the plugin's main functionalities.
 * This function will be hooked to 'plugins_loaded'.
 */
function rank_initialize_plugin_components() {
    // Check if we need to update the database
    $installed_db_version = get_option('rank_db_version');
    if ($installed_db_version !== RANK_DB_VERSION) {
        rank_update_db_check();
    }
    
    // Action Scheduler is already included globally.
    // --- Initialize Plugin Components ---

    // Initialize Admin Area functionality (Menu, Scripts, Settings)
    Rank_Admin::init();

    // Initialize AJAX handlers
    Rank_Ajax::init();
    
    // Add a global AJAX action to set up abort handling for all AJAX requests
    add_action('wp_ajax_', function() {
        // Tell PHP to stop execution when the client disconnects
        ignore_user_abort(false);
        
        // Set a reasonable timeout for all AJAX requests
        set_time_limit(30);
    });

    // Initialize Action Scheduler Task Processor
    Rank_Processor::init();

    // Initialize Frontend Filters
    Rank_Frontend_Filters::init();
    
    // Initialize URL List functionality
    Rank_URL_List::init();
    
    // Initialize Rank Writer functionality
    Rank_Writer::init();

    // --- ADD ACTION SCHEDULER BATCH SIZE FILTER ---
    // Add this filter now that Action Scheduler should be loaded.
    add_filter( 'action_scheduler_queue_runner_batch_size', 'rank_filter_action_scheduler_batch_size_callback' ); // Renamed for clarity
}
// Use a priority that allows other plugins (like WooCommerce, which also uses AS) to load first if necessary.
// A priority of 20: Safe bet.
add_action( 'plugins_loaded', 'rank_initialize_plugin_components', 20 );

/**
 * Callback function for filtering Action Scheduler batch size.
 * and to follow a more common callback naming pattern.
 */
function rank_filter_action_scheduler_batch_size_callback( $batch_size ) {
    // Set batch size to 1 due to long-running API calls.
    return 1;
}

/**
 * Check if database needs to be updated and run the update if needed
 */
function rank_update_db_check() {
    if (get_option('rank_db_version') != RANK_DB_VERSION) {
        rank_activate_plugin();
    }
}

/**
 * Fix autoload settings for specific RANK plugin options
 * This runs during plugin activation and updates
 */
function rank_fix_autoload_settings() {
    global $wpdb;
    
    // Specific options that should never be autoloaded
    $options_to_fix = array(
        'rank_internal_url_replacements',
        'rank_external_url_replacements',
        'rank_db_version',
        'rank_debug_enabled'
    );
    
    foreach ($options_to_fix as $option_name) {
        // Check if option exists and has wrong autoload setting
        $current_autoload = $wpdb->get_var($wpdb->prepare(
            "SELECT autoload FROM {$wpdb->options} WHERE option_name = %s",
            $option_name
        ));
        
        // Fix if it's set to 'yes' or 'auto' (both mean autoloaded)
        if ($current_autoload === 'yes' || $current_autoload === 'auto') {
            $wpdb->update(
                $wpdb->options,
                array('autoload' => 'no'),
                array('option_name' => $option_name),
                array('%s'),
                array('%s')
            );
            
            error_log("RANK Plugin: Fixed autoload setting for {$option_name} (was: {$current_autoload}, now: no)");
        }
    }
    
    // Also fix any batch options that might exist
    $wpdb->query("UPDATE {$wpdb->options} SET autoload = 'no' WHERE option_name LIKE 'batch_%' AND autoload IN ('yes', 'auto')");
}


/**
 * Check for system issues and display admin notices.
 */
function rank_check_system_status() {
    // Only run on admin pages
    if (!is_admin()) {
        return;
    }
    
    // Check if main table exists - that's what matters most
    $table_exists = Rank_Processor::check_table_exists();
    
    if (!$table_exists) {
        add_action('admin_notices', function() {
            echo '<div class="error"><p>';
            echo '<strong>Rank AI Plugin:</strong> Database table missing. ';
            echo 'Try deactivating and reactivating the plugin to create the table.';
            echo '</p></div>';
        });
        return; // If table doesn't exist, no point checking other things
    }
    
    // Check Action Scheduler
    $action_scheduler = Rank_Processor::check_action_scheduler();
    
    if (!$action_scheduler['exists'] || !$action_scheduler['hooks_registered']) {
        add_action('admin_notices', function() {
            echo '<div class="notice notice-warning"><p>';
            echo '<strong>Rank AI Plugin:</strong> Action Scheduler is not properly configured. ';
            echo 'This will prevent scheduled SEO fixes from running.';
            echo '</p></div>';
        });
    }
}
add_action('admin_init', 'rank_check_system_status');

?>
