<?php

namespace XZD\AI\V5\Tools;

use XZD\AI\V5\AI\Client;

/**
 * 中文分词器 — 利用 AI 模型做智能语义分词
 *
 * 中文没有空格分隔词，传统 LIKE 几乎无法匹配。
 * 调用轻量 AI 做语义分词后多关键词 OR 查询，结果缓存 1 小时。
 */
class ChineseTokenizer
{
    private Client $ai;

    public function __construct(?Client $ai = null)
    {
        $this->ai = $ai ?? Client::instance();
    }

    /**
     * 对中文文本分词，返回关键词数组
     */
    public function segment(string $text): array
    {
        // 纯英文/数字直接按空格分词，不需要 AI
        if (preg_match('/^[\x00-\x7F\s\d]+$/u', trim($text))) {
            $tokens = preg_split('/\s+/', trim($text));
            return array_values(array_filter($tokens, fn($t) => mb_strlen($t) > 1));
        }

        // 检查缓存
        $cacheKey = 'xzd_token_' . md5($text);
        $cached = get_transient($cacheKey);
        if ($cached !== false && is_array($cached)) {
            return $cached;
        }

        // AI 分词
        try {
            $tokens = $this->aiSegment($text);
            if (!empty($tokens)) {
                set_transient($cacheKey, $tokens, HOUR_IN_SECONDS);
                return $tokens;
            }
        } catch (\Throwable $e) {
            // AI 不可用时降级为 N-gram 切分
        }

        // 降级: 按 UTF-8 字符切分 + 2-gram
        $fallback = $this->ngramSegment($text, 2);
        set_transient($cacheKey, $fallback, HOUR_IN_SECONDS);
        return $fallback;
    }

    /**
     * 调用 AI 做分词
     */
    private function aiSegment(string $text): array
    {
        $prompt = <<<'EOT'
## 分词任务
将以下中文文本切分为有意义的关键词。每个关键词2-4个字。

## 规则
- 输出纯 JSON 数组，不要任何解释
- 去掉"的"、"了"、"是"、"在"、"和"、"与"等停用词
- 保留人名、术语、专有名词

## 示例
输入: "如何使用人工智能生成高质量文章"
输出: ["人工智能", "生成", "高质量", "文章"]

## 输入文本
{$text}
EOT;
        $result = $this->ai->chatStructured(
            [['role' => 'user', 'content' => $prompt]],
            ['type' => 'object', 'properties' => ['keywords' => ['type' => 'array', 'items' => ['type' => 'string']]], 'required' => ['keywords']],
            ['max_tokens' => 200, 'temperature' => 0.1]
        );

        if (is_array($result) && !empty($result)) {
            // 结构化输出返回 {'keywords': [...]}，取 keywords 字段
            $keywords = $result['keywords'] ?? $result;
            if (!is_array($keywords) || empty($keywords)) return [];
            return array_values(array_filter($keywords, fn($t) =>
                is_string($t) && mb_strlen($t) >= 2 && $t !== $text
            ));
        }

        return [];
    }

    /**
     * N-gram 降级分词（无 AI 时）
     */
    public function ngramSegment(string $text, int $n = 2): array
    {
        $chars = preg_split('//u', $text, -1, PREG_SPLIT_NO_EMPTY);
        $len = count($chars);
        $tokens = [];

        for ($i = 0; $i <= $len - $n; $i++) {
            $tokens[] = implode('', array_slice($chars, $i, $n));
        }

        // 去重 + 过滤纯标点
        $stopwords = ['的', '了', '是', '在', '和', '与', '我', '你', '他', '她', '它', '们', '这', '那', '么', '吗', '吧', '啊'];
        return array_values(array_unique(array_filter($tokens, fn($t) =>
            !in_array($t, $stopwords, true)
        )));
    }
}
