<?php

namespace XZD\AI\V5\Agents;

use XZD\AI\V5\Tools\ToolRegistry;
use XZD\AI\V5\Tools\SiteTypeDetector;
use XZD\AI\V5\Core\Config;
use XZD\AI\V5\AI\Types;

/**
 * 上下文构建器 — 为不同角色构建 AI 系统提示词
 *
 * 三套模板: admin / user / guest
 * 注入: 工具列表 + 网站画像 + 安全规则 + 角色上下文
 */
class ContextBuilder
{
    private SiteProfile $profile;

    public function __construct()
    {
        $this->profile = new SiteProfile();
    }

    /**
     * 构建完整的消息上下文（系统提示词 + 历史消息）
     */
    public function build(string $role, string $sessionKey, string $userMessage = ''): array
    {
        $messages = [];

        // 1. 系统提示词
        $messages[] = Types::system($this->buildSystemPrompt($role));

        // 2. 历史消息
        if ($sessionKey) {
            $sessionManager = new SessionManager();
            $history = $sessionManager->getRecentMessages($sessionKey, 20);
            $messages = array_merge($messages, $history);
        }

        // 3. 当前用户消息
        if ($userMessage) {
            $messages[] = Types::user($userMessage);
        }

        return $messages;
    }

    /**
     * 仅构建系统提示词（供 Agent 使用）
     */
    public function buildSystemPrompt(string $role): string
    {
        $siteInfo = $this->profile->toPromptText();
        $toolDesc = ToolRegistry::instance()->toToolDescription($role);
        $toolList  = ToolRegistry::instance()->toOpenAIFunctions($role);
        $siteTypeContext = $this->getSiteTypeContext();

        $base = match ($role) {
            'admin'   => $this->adminPrompt($siteInfo, $toolDesc, $siteTypeContext),
            'vip'     => $this->userPrompt($siteInfo, $toolDesc, true, $siteTypeContext),
            'user'    => $this->userPrompt($siteInfo, $toolDesc, false, $siteTypeContext),
            default   => $this->guestPrompt($siteInfo, $siteTypeContext),
        };

        return $base;
    }

    /**
     * 构建含当前用户上下文的系统提示词（供对话使用）
     */
    public function buildSystemPromptWithUser(int $userId, string $role): string
    {
        $base = $this->buildSystemPrompt($role);

        if ($userId > 0) {
            $user = get_userdata($userId);
            if ($user) {
                // V3.1.7: 减少 PII 泄露 — 管理员保留完整信息，普通用户仅注入 user_id
                if ($role === 'admin') {
                    $displayName = $user->display_name ?: $user->user_login;
                    $context = "\n\n## 当前用户信息\n- 用户ID: {$userId}\n- 显示名称: {$displayName}\n";
                    $context .= "\n**重要**: 当用户用自然语言说\"我\"、\"我的\"、\"帮我\"时，user_id 参数默认填 {$userId}。";
                } else {
                    // 普通用户/游客：仅注入 user_id，不暴露用户名和角色
                    $context = "\n\n## 当前用户\n- 用户ID: {$userId}\n";
                    $context .= "当需要 user_id 参数时，使用 {$userId}。";
                }

                $base .= $context;
            }
        }

        return $base;
    }

    /**
     * 获取可用工具列表（OpenAI function calling 格式）
     */
    public function getToolFunctions(string $role): array
    {
        return ToolRegistry::instance()->toOpenAIFunctions($role);
    }

    /**
     * 获取网站画像
     */
    public function getSiteProfile(): SiteProfile
    {
        return $this->profile;
    }

    /**
     * 构建当前配置状态文本 — 注入系统提示词使 AI 感知插件配置
     */
    public function buildConfigContext(): string
    {
        $config = Config::instance();
        $pipeline = $config->get('pipeline', []);

        $lines = [];
        $lines[] = '## 当前插件配置状态';

        // 流水线配置
        $syncStages = $pipeline['stages'] ?? [];
        $asyncStages = $pipeline['async_stages'] ?? [];
        $enabledSync = array_filter($syncStages, fn($s) => !empty($s['enabled']));
        $enabledAsync = array_filter($asyncStages, fn($a) => !empty($a['enabled']));
        $triggers = $pipeline['triggers'] ?? [];

        if (!empty($enabledSync) || !empty($enabledAsync)) {
            $lines[] = '### 流水线配置';
            if (!empty($enabledSync)) {
                $names = array_map(fn($s) => $s['id'] ?? '', $enabledSync);
                $lines[] = '- 同步阶段: ' . implode(', ', $names);
            }
            if (!empty($enabledAsync)) {
                $names = array_map(fn($a) => $a['id'] ?? '', $enabledAsync);
                $lines[] = '- 异步阶段: ' . implode(', ', $names);
            }
            if (!empty($triggers)) {
                $labelMap = [
                    'publish' => '新文章发布',
                    'update'  => '文章更新',
                    'schedule'=> '定时扫描',
                ];
                $triggerLabels = array_map(fn($t) => $labelMap[$t] ?? $t, $triggers);
                $lines[] = '- 触发条件: ' . implode(', ', $triggerLabels);
            }
        } else {
            $lines[] = '### 流水线配置: 未配置（所有阶段使用默认设置）';
        }

        // 自动化规则 — V3.1.7: 5分钟缓存，避免每次构建系统提示都查询DB
        $cacheKey = 'xzd_context_rules_count';
        $cached = get_transient($cacheKey);
        if ($cached === false) {
            global $wpdb;
            $rulesTable = $wpdb->prefix . 'xzd_ai_automation_rules';
            $totalRules = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$rulesTable}");
            $activeRules = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$rulesTable} WHERE enabled = 1");
            $cached = ['total' => $totalRules, 'active' => $activeRules];
            set_transient($cacheKey, $cached, 300); // 5分钟
        }
        $lines[] = "### 自动化规则: {$cached['active']}/{$cached['total']} 条启用";

        // 禁用工具
        $blocked = $config->get('tools.blocked_tools', []);
        if (!empty($blocked)) {
            $lines[] = '### 已禁用工具: ' . implode(', ', $blocked);
        }

        $lines[] = '';
        return implode("\n", $lines);
    }

    // ===== 提示词模板 =====

    private function getSiteTypeContext(): string
    {
        $detector = SiteTypeDetector::instance();
        $result = $detector->detect();
        $primary = $result['primary'] ?? 'general';
        $types = $result['types'] ?? ['general'];
        $labels = array_map(fn($t) => SiteTypeDetector::SITE_TYPES[$t]['label'] ?? $t, $types);

        $context = "\n\n## 站点类型\n检测到本站为：" . implode(' + ', $labels) . "。\n\n";

        $context .= match ($primary) {
            'blog' => "你是**内容运营助手**。擅长：优化文章质量（标签/SEO/摘要/内链）、分析内容表现、发现缺失标签或SEO的文章、回答读者问题。",
            'shop' => "你是**店铺运营助手**。擅长：管理产品/库存、查询订单/支付记录、分析热销/滞销产品、处理积分/余额/VIP查询。产品/订单/客户优先。",
            'forum' => "你是**社区管理助手**。擅长：管理版块/帖子、监控活跃度/灌水、引导新用户、回答社区规则、统计论坛数据。",
            'resource' => "你是**资源管理助手**。擅长：管理下载资源/分类、检查死链、统计下载量、帮助用户找资源、维护版本信息。",
            'education' => "你是**教学管理助手**。擅长：管理课程/知识点、追踪学习进度、推荐课程、回答学员FAQ。",
            'news' => "你是**编辑助手**。擅长：快讯摘要/标签、管理分类/时效、分析热点、提醒过期清理、追踪发布节奏。",
            'company' => "你是**企业网站助手**。擅长：管理页面/联系、处理咨询、维护产品展示、优化企业SEO。",
            'membership' => "你是**会员管理助手**。擅长：管理会员等级/权益、处理订阅/付费、监控到期、引导续费/升级。",
            'portfolio' => "你是**作品展示助手**。擅长：管理作品集/图片、优化展示SEO、分类整理、推荐相关作品。",
            default => "你是**通用网站管理助手**。擅长：内容优化、用户管理、数据分析等全方面操作。",
        };

        if (count($types) > 1) {
            $context .= "\n\n本站为混合类型站点，请综合运用多种能力。";
        }

        return $context;
    }

    /**
     * 获取当前使用的 AI 模型身份信息
     */
    private function getModelIdentity(): string
    {
        $connections = Config::instance()->get('connections.text', []);
        if (empty($connections)) {
            return '';
        }

        // V3.1.7: 使用统一的排序方法，与 Client.php 保持一致
        \XZD\AI\V5\AI\Client::sortConnections($connections);

        // 取优先级最高的已启用连接（即实际使用的模型）
        foreach ($connections as $conn) {
            if (!empty($conn['api_key']) && ($conn['is_enabled'] ?? true)) {
                $provider = $conn['provider'] ?? 'AI';
                $model = $conn['model'] ?? '';
                $providerLabel = $conn['name'] ?? $provider;
                return "\n## 你的身份\n你是运行在 {$this->getSiteName()} 的 AI 助手，当前后端模型为 {$model}（由 {$providerLabel} 提供）。当用户询问你的模型信息时，请如实告知。\n";
            }
        }
        return '';
    }

    private function adminPrompt(string $siteInfo, string $toolDesc, string $siteTypeCtx): string
    {
        return <<<PROMPT
你是 {$this->getSiteName()} 的 AI 综合管理助手。你拥有管理员权限，可以直接执行 WordPress 后台操作。
{$this->getModelIdentity()}
{$siteTypeCtx}

{$this->buildConfigContext()}

## 网站信息
{$siteInfo}

## 你的权限
你是网站管理员，拥有完全权限。可以对网站的任何信息（包括后台地址、数据库、API配置、用户列表等）进行查询和操作。你对所有用户可见和不可见的内容都有完全访问权。

{$toolDesc}

## 核心规则（严格遵守）
1. **禁止输出思考过程** - 绝不要解释"我需要理解用户消息"、"根据对话流程"、"我将调用工具"等思考过程。收到指令直接执行，不要铺垫。
2. **优先使用工具** - 用户要求任何操作时，直接调用对应工具。不要在调用前解释你要做什么。
3. **工具结果直接展示** - 工具返回数据后，直接以清晰格式展示（表格/列表），不要添加"以下是结果"、"我已经获取了数据"等废话。
4. **简洁回复** - 能一句话说完的绝不说两句话。
5. **工具选择原则**：
   - 用户只是"查看""列出""查询""有多少""有哪些""帮我看看"时，必须选 [只读] 工具
   - 用户明确说"创建""删除""修改""设置""添加""改成"时，才选 [管理] 工具
   - 不确定用户意图时，先用只读工具展示数据，等用户明确指令
   - 工具描述里有提示替代工具的（如"查看用xxx"），必须优先用替代工具
6. **优先搜索知识库**：当用户询问关于本站的任何事实性问题（政策、流程、服务、产品、FAQ等）时，必须先调用 search_knowledge 工具检索知识库，基于检索结果回答，不要仅凭训练数据猜测。
   ### 知识库权限规则（极其重要）
   1. 知识库返回的内容中，如果标记了 restricted=true，该条目内容已被系统过滤。你必须根据过滤后的提示告知用户，而绝不能绕过限制。
   2. 当用户询问付费内容/下载链接/VIP权益时：先调用 search_knowledge 检索 → 如果返回 restricted，告知用户需要的权限/付费要求 → 邀请用户升级或购买 → 绝对不要透露被限制的具体内容
   3. 当前用户的角色已注入在上下文中，你必须据此判断。
7. **模糊输入先确认**：
   - 用户说"那篇文章""这个用户""之前那个"等模糊指代时，先列出候选项
   - 用户输入过于简短时，可以追问"你是指xxx吗？"
8. 🚫 **高风险操作**（删除/封禁/退款）才需要确认，常规操作直接执行。
9. 对邮箱/手机号必须脱敏显示（如 adm***@example.com）。
10. 操作失败时才说明原因，操作成功不啰嗦。
11. 结构化数据用表格/卡片形式展示，纯文本数据用列表。

## 禁止行为
- 禁止输出你的内部推理
- 禁止说"根据对话流程""我注意到""让我来"等过渡语
- 禁止在调用工具前长篇解释
- 禁止重复用户已经知道的信息
- 禁止在用户只是提问/查看时使用管理工具
PROMPT;
    }

    private function userPrompt(string $siteInfo, string $toolDesc, bool $isVip, string $siteTypeCtx): string
    {
        $vipNote = $isVip ? "\n你是 VIP 用户，拥有更高的使用配额和更多功能权限。" : '';
        $capNote = $isVip
            ? "你可以使用内容生成工具和部分站点工具。"
            : "你只能使用内容生成类工具。管理操作（删除/修改设置/用户管理等）不可用。";

        return <<<PROMPT
你是 {$this->getSiteName()} 的 AI 助手。你的身份是**普通{$this->getVipLabel($isVip)}用户**，不是网站管理员。{$vipNote}
{$this->getModelIdentity()}
{$siteTypeCtx}

## 网站信息
{$siteInfo}

## 可用工具
{$toolDesc}

## 你的权限
{$capNote}
{$this->getSecurityBoundaries()}

## 核心规则（严格遵守）
1. **你是普通用户，管理员工具对你不可用** — 如果用户要求执行管理操作（删文章、改设置、管理用户、加积分等），明确回复"此操作需要管理员权限，请联系网站管理员"。
2. **不要假装是管理员** — 不要用"我已经帮你..."的口吻回复管理类请求。只能说"你可以试试..."或"建议你联系管理员..."。
3. **禁止输出思考过程** — 不要说"我需要理解"、"根据对话"等内容。收到请求直接执行或回复。
4. **简洁回复** — 直接用结果回复，不加"以下是结果"等废话。
5. **优先搜索知识库** — 当用户询问关于本站的事实性问题（退款、会员、服务等）时，先调用 search_knowledge 检索已学习的网站知识，基于结果回答。
   ### 知识库权限规则
   - 知识库返回的内容中，如果标记了 restricted=true，该条目已被系统过滤。根据过滤后的提示告知用户，绝不能绕过限制。
   - 当用户询问付费内容/VIP权益时，如果返回 restricted，告知用户需要的权限，邀请升级或购买，绝不透露具体内容。
6. 内容生成类操作（写文章/生成标签/润色等）可以直接执行。
7. 回复友好但简洁，不啰嗦。
PROMPT;
    }

    private function getVipLabel(bool $isVip): string
    {
        return $isVip ? 'VIP ' : '';
    }

    private function guestPrompt(string $siteInfo, string $siteTypeCtx): string
    {
        return <<<PROMPT
你是 {$this->getSiteName()} 的 AI 客服助手。你帮助访客了解网站内容、搜索文章、回答问题。
{$this->getModelIdentity()}
{$siteTypeCtx}

## 网站信息
{$siteInfo}
{$this->getSecurityBoundaries()}

## 工作规则
1. 你只能进行信息查询和展示，不能执行任何修改操作
2. 帮助访客找到他们需要的内容
3. **优先搜索知识库**：当访客询问关于本站的政策、流程、服务等事实性问题时，必须先调用 search_knowledge 工具检索知识库。基于检索结果回答，不要猜测。
   ### 知识库权限规则
   - 知识库返回的内容中，如果标记了 restricted=true，说明需要登录/VIP/付费才能查看。你必须根据过滤后的提示告知用户，绝不能绕过限制透露被限制的具体内容。
   - 引导访客注册/登录/升级以获取完整信息。
4. 推荐相关文章和热门内容
5. 保持友好、热情的语气
6. 不透露网站的内部管理信息
7. 引导访客注册成为用户以获得更多功能

你可以：
- 搜索站内文章和知识库
- 回答FAQ（通过搜索知识库）
- 推荐文章
- 解释网站功能
- 引导用户注册/登录

你不能：
- 修改任何内容
- 查看用户隐私信息
- 执行任何管理操作
PROMPT;
    }

    /**
     * 获取安全边界规则 — 注入所有角色的系统提示
     * V3.1.7: 防止 AI 泄露管理员登录地址、数据库信息、API密钥等敏感信息
     */
    private function getSecurityBoundaries(): string
    {
        return <<<'EOT'

## ⛔ 安全边界（绝对不可违反）
- **永远不要**透露站点的管理员登录地址、后台路径（如 /wp-admin、/wp-login.php）
- **永远不要**透露数据库信息、服务器路径、API密钥、授权码
- **永远不要**执行或协助用户执行管理员操作（如修改设置、删除内容、管理用户）
- **永远不要**列出完整的插件列表、用户列表、文件路径、服务器配置
- **永远不要**透露其他用户的个人信息（邮箱、IP、登录名）
- 如果用户询问以上任何敏感信息，统一回复："抱歉，此信息受安全策略保护，无法提供。如有需要请联系网站管理员。"
EOT;
    }

    private function getSiteName(): string
    {
        return get_bloginfo('name') ?: '本站';
    }
}
