<?php

/**
 * LolaCore - SkillInjector
 *
 * Hooks into the `lolacore_system_prompt` filter with priority 20 and
 * appends a SKILLS block containing the bodies of skills that matched
 * the current user message. The current message is published via a
 * static slot set by WPAIClientAdapter::buildSystemPrompt() right
 * before SystemPromptBuilder::build() runs.
 *
 * The static slot is cleared automatically on the `shutdown` action so
 * a long-running PHP process cannot leak context across requests.
 *
 * @package LolaCore
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\Skills;

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

class SkillInjector
{
    public const FILTER_HOOK    = 'lolacore_system_prompt';
    public const FILTER_PRIORITY = 20;

    private static string $currentMessage = '';
    private static string $currentIntent  = '';

    private SkillMatcher $matcher;
    private SkillRegistry $registry;

    public function __construct(SkillMatcher $matcher, SkillRegistry $registry)
    {
        $this->matcher  = $matcher;
        $this->registry = $registry;
    }

    /**
     * Hook into the system prompt filter.
     */
    public function register(): void
    {
        if (!function_exists('add_filter')) {
            return;
        }
        add_filter(self::FILTER_HOOK, [$this, 'inject'], self::FILTER_PRIORITY, 1);
    }

    /**
     * Publish the message + intent context that the next system-prompt
     * build will consume. Call this from the chat orchestrator before
     * SystemPromptBuilder::build() runs.
     */
    public static function setCurrentMessage(string $message, string $intent = ''): void
    {
        self::$currentMessage = mb_strtolower(trim($message), 'UTF-8');
        self::$currentIntent  = $intent;
    }

    /**
     * Clear the static slot (called on `shutdown`).
     */
    public static function resetContext(): void
    {
        self::$currentMessage = '';
        self::$currentIntent  = '';
    }

    public static function getCurrentMessage(): string
    {
        return self::$currentMessage;
    }

    public static function getCurrentIntent(): string
    {
        return self::$currentIntent;
    }

    /**
     * Filter callback — append matched skill bodies to the prompt.
     */
    public function inject(string $prompt): string
    {
        $matched = $this->matcher->match(self::$currentMessage, self::$currentIntent);
        if ($matched === []) {
            return $prompt;
        }

        $bodies = [];
        foreach ($matched as $skill) {
            $body = trim($skill->getBody());
            if ($body !== '') {
                $bodies[] = $body;
            }
        }

        if ($bodies === []) {
            return $prompt;
        }

        $this->touchUsage($matched);

        $block = "SKILLS:\n" . implode("\n\n", $bodies);
        return $prompt . "\n\n" . $block;
    }

    /**
     * Bump load_count + last_used_at for DB-origin skills. Best-effort,
     * inline (single indexed write), zero blocking.
     *
     * @param array<int, Skill> $matched
     */
    private function touchUsage(array $matched): void
    {
        if (!isset($GLOBALS['wpdb']) || !is_object($GLOBALS['wpdb'])) {
            return;
        }
        $wpdb = $GLOBALS['wpdb'];
        if (!method_exists($wpdb, 'query') || !method_exists($wpdb, 'prepare')) {
            return;
        }
        $prefix = property_exists($wpdb, 'prefix') ? $wpdb->prefix : '';
        $table  = $prefix . 'lolacore_skills';

        $now = function_exists('current_time') ? (string) current_time('mysql') : gmdate('Y-m-d H:i:s');

        foreach ($matched as $skill) {
            if ($skill->getOrigin() !== Skill::ORIGIN_DB) {
                continue;
            }
            @$wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $table is built from $wpdb->prefix constant.
                $wpdb->prepare(
                    "UPDATE {$table} SET load_count = load_count + 1, last_used_at = %s WHERE skill_name = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table is built from $wpdb->prefix constant.
                    $now,
                    $skill->getName()
                )
            );
        }
    }
}
