<?php
/**
 * Plugin Name: LolaCore – AI Admin Agent
 * Plugin URI:  https://lolacore.com
 * Description: An AI agent inside your wp-admin that remembers your site between sessions. 51 abilities across plugins, content, SEO, security, users, and WooCommerce — managed through conversation.
 * Version:     1.6.3
 * Author:      Fran Barbero
 * Author URI:  https://profiles.wordpress.org/vanguardhive/
 * License:     GPL-2.0-or-later
 * Text Domain: lolacore
 * Domain Path: /languages
 * Requires at least: 7.0
 * Requires PHP: 8.0
 *
 * @package LolaCore
 */

declare(strict_types=1);

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

// Require Composer Autoloader (via Jetpack Autoloader for shared-library "latest version wins" resolution)
if (file_exists(__DIR__ . '/vendor/autoload_packages.php')) {
    require_once __DIR__ . '/vendor/autoload_packages.php';
} elseif (file_exists(__DIR__ . '/vendor/autoload.php')) {
    // Fallback for tests / dev installs where JA hasn't generated yet.
    require_once __DIR__ . '/vendor/autoload.php';
}

// Bootstrap the bundled WP MCP Adapter (idempotent singleton).
// We ship our own copy via composer + Jetpack Autoloader so we never depend on the
// standalone `mcp-adapter` plugin being installed. JA's "latest version wins" also
// ensures we beat the older v0.1.0 copy vendored inside WooCommerce.
if (class_exists(\WP\MCP\Plugin::class)) {
    \WP\MCP\Plugin::instance();
}

// Define Plugin Constants
define('LOLACORE_VERSION', '1.6.3');
define('LOLACORE_DB_VERSION', '0.3.0');
define('LOLACORE_PLUGIN_FILE', __FILE__);
define('LOLACORE_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('LOLACORE_PLUGIN_URL', plugin_dir_url(__FILE__));

/**
 * Phase-Out Refactoring Feature Flag.
 *
 * Controls whether ActionExecutor delegates to the new Domain Handler system
 * (HandlerRouter + individual Handlers) or uses its internal methods directly.
 *
 * false = legacy monolithic behavior (safe default during migration).
 * true  = new Domain Handler system (activated in Phase 4 after full migration).
 *
 * Can be overridden in wp-config.php:
 *   define('LOLACORE_USE_DOMAIN_HANDLERS', true);
 */
if (!defined('LOLACORE_USE_DOMAIN_HANDLERS')) {
    define('LOLACORE_USE_DOMAIN_HANDLERS', true);
}

/**
 * Sprint 3 — Async extractFacts feature flag.
 *
 * When true (default), memory fact extraction runs after the HTTP response
 * is closed via fastcgi_finish_request(), removing ~5-19s of LLM latency
 * from the user-perceived response time. Requires PHP-FPM (verified during
 * Sprint 0 baseline capture).
 *
 * Override in wp-config.php to disable:
 *   define('LOLACORE_ASYNC_EXTRACT_FACTS', false);
 */
if (!defined('LOLACORE_ASYNC_EXTRACT_FACTS')) {
    define('LOLACORE_ASYNC_EXTRACT_FACTS', true);
}

// Early exit if WP AI Client is not available (requires WP 7.0+)
if (!function_exists('wp_ai_client_prompt')) {
    add_action('admin_notices', function () {
        echo '<div class="notice notice-error"><p>LolaCore requires the WordPress Abilities API (feature plugin) or WordPress 7.0+.</p></div>';
    });
    return;
}

// Initialization Hook
add_action('plugins_loaded', function () {

    // DB Migration Check
    if (class_exists(\LolaCore\Database\Migrator::class)) {
        \LolaCore\Database\Migrator::maybeUpgrade();
    }

    // Register Admin Modules
    if (is_admin()) {
        $assets = new \LolaCore\Admin\Assets();
        $assets->register();

        $menu = new \LolaCore\Admin\Menu();
        $menu->register();

        $settings = new \LolaCore\Admin\Settings();
        $settings->register();

        $widget = new \LolaCore\Admin\Widget();
        $widget->register();
    }

    // Register Chat Backend Endpoints (AJAX can be called from admin or frontend if exposed later)
    if (class_exists(\LolaCore\Chat\Controller::class)) {
        $chatController = new \LolaCore\Chat\Controller();
        $chatController->register();
    }

    // Register LLM Providers
    if (class_exists(\LolaCore\LLM\ProviderRegistrar::class)) {
        $registrar = new \LolaCore\LLM\ProviderRegistrar();
        $registrar->register();
    }

    // Register Actions & Abilities
    if (class_exists(\LolaCore\Actions\AbilitiesRegistry::class)) {
        $abilitiesRegistry = new \LolaCore\Actions\AbilitiesRegistry();
        $abilitiesRegistry->register();
    }

    // Register MCP Server with the WP MCP Adapter (creates /wp-json/mcp/lolacore endpoint)
    if (class_exists(\LolaCore\Admin\McpServerRegistrar::class)) {
        $mcpRegistrar = new \LolaCore\Admin\McpServerRegistrar();
        $mcpRegistrar->register();
    }

    // Register Hub Endpoints (REST API — future Hub Pro connectivity)
    if (class_exists(\LolaCore\Hub\DiscoverEndpoint::class)) {
        $discover = new \LolaCore\Hub\DiscoverEndpoint();
        $discover->register();
    }

    if (class_exists(\LolaCore\Hub\ConnectEndpoint::class)) {
        $connect = new \LolaCore\Hub\ConnectEndpoint();
        $connect->register();
    }

    if (class_exists(\LolaCore\Hub\SyncEndpoint::class)) {
        $sync = new \LolaCore\Hub\SyncEndpoint();
        $sync->register();
    }

    // Register Skills.MD engine (v1.4.0).
    // Stack: YamlParser -> SkillValidator -> SkillLoader -> SkillRegistry
    //        -> SkillMatcher -> SkillInjector (filter listener).
    if (class_exists(\LolaCore\Skills\SkillInjector::class)) {
        $parser    = new \LolaCore\Skills\YamlParser();
        $validator = new \LolaCore\Skills\SkillValidator();
        $loader    = new \LolaCore\Skills\SkillLoader($parser, $validator);
        $registry  = new \LolaCore\Skills\SkillRegistry($loader);
        $registry->load();
        $matcher  = new \LolaCore\Skills\SkillMatcher($registry);
        $injector = new \LolaCore\Skills\SkillInjector($matcher, $registry);
        $injector->register();
    }
});

// Skills.MD: clear static request context at the end of every request so
// the message slot cannot leak across long-running PHP processes.
add_action('shutdown', [\LolaCore\Skills\SkillInjector::class, 'resetContext']);

// Memory Bootstrap: register cron interval and handler.
// Priority 30 on init ensures this runs AFTER all addons have registered,
// and prevents premature DB writes that trigger WP 6.7 translation notices.
add_action('init', function () {
    if (!class_exists(\LolaCore\Memory\MemoryBootstrapRunner::class)) {
        return;
    }

    // Register the 'six_hours' cron schedule
    add_filter('cron_schedules', [\LolaCore\Memory\MemoryBootstrapRunner::class, 'registerCronInterval']);

    // Schedule the unified cron if not already scheduled
    $runner = new \LolaCore\Memory\MemoryBootstrapRunner();
    $runner->scheduleRefresh();

    // Handle the cron callback
    add_action(\LolaCore\Memory\MemoryBootstrapRunner::CRON_HOOK, [$runner, 'handleCron']);
}, 30);

// Run the deferred initial scan once, the first request after activation.
// At this point active_plugins and other options are fully persisted, so
// the snapshot reflects reality.
add_action('init', function () {
    if (!get_option('lolacore_pending_initial_scan')) {
        return;
    }
    if (!class_exists(\LolaCore\Activation::class)) {
        require_once __DIR__ . '/src/Activation.php';
    }
    \LolaCore\Activation::runInitialScan();
    delete_option('lolacore_pending_initial_scan');
}, 20);

// Memory Bootstrap: retroactive run for addons that haven't seeded yet.
// Runs once per boot cycle if new bootstraps are discovered.
add_action('init', function () {
    if (!class_exists(\LolaCore\Memory\MemoryBootstrapRunner::class)) {
        return;
    }
    $timestamps = get_option('lolacore_bootstrap_timestamps', []);
    if (empty($timestamps)) {
        // No timestamps = never run. Force a full bootstrap on first init.
        $runner = new \LolaCore\Memory\MemoryBootstrapRunner();
        $runner->runAllForced();
    }
}, 25);

// Activation Hook
register_activation_hook(__FILE__, function () {
    require_once __DIR__ . '/src/Activation.php';
    \LolaCore\Activation::run();
});

// Deactivation Hook
register_deactivation_hook(__FILE__, function () {
    require_once __DIR__ . '/src/Deactivation.php';
    \LolaCore\Deactivation::run();

    // Unschedule bootstrap cron
    if (class_exists(\LolaCore\Memory\MemoryBootstrapRunner::class)) {
        \LolaCore\Memory\MemoryBootstrapRunner::unschedule();
    }
});
