<?php

namespace XZD\AI\V5\Agents;

use XZD\AI\V5\AI\Client;
use XZD\AI\V5\AI\Types;
use XZD\AI\V5\Tools\ToolRegistry;
use XZD\AI\V5\Core\Logger;

/**
 * Agent 基类 — 所有专业 Agent 的抽象基类
 *
 * 封装: 系统提示词获取 / 工具列表过滤 / AI 调用 / 结果格式化
 */
abstract class BaseAgent
{
    protected ContextBuilder $context;

    public function __construct()
    {
        $this->context = new ContextBuilder();
    }

    /**
     * Agent 唯一标识
     */
    abstract public function getId(): string;

    /**
     * Agent 显示名称
     */
    abstract public function getName(): string;

    /**
     * Agent 描述
     */
    abstract public function getDescription(): string;

    /**
     * 获取工具分类过滤白名单
     * 返回 [] 表示所有工具可见（管理员级别）
     */
    abstract public function getToolCategories(): array;

    /**
     * 获取此 Agent 适用的用户角色
     */
    abstract public function getMinRole(): string;

    /**
     * 构建系统提示词（可选传入用户ID以包含用户上下文）
     */
    public function getSystemPrompt(string $role, int $userId = 0): string
    {
        if ($userId > 0) {
            return $this->context->buildSystemPromptWithUser($userId, $role);
        }
        return $this->context->buildSystemPrompt($role);
    }

    /**
     * 获取可用工具列表（按分类过滤）
     */
    public function getTools(string $role): array
    {
        $categories = $this->getToolCategories();
        $allTools = ToolRegistry::instance()->getAvailable($role);

        if (empty($categories)) {
            return $allTools;
        }

        return array_filter($allTools, function ($tool) use ($categories) {
            $cat = is_object($tool) ? $tool->category : ($tool['category'] ?? '');
            return in_array($cat, $categories, true);
        });
    }

    /**
     * 获取 OpenAI function calling 格式的工具列表
     */
    public function getToolFunctions(string $role): array
    {
        $tools = $this->getTools($role);
        return array_values(array_map(
            fn($t) => $t->toOpenAIFunction(),
            $tools
        ));
    }

    /**
     * 执行非流式对话
     */
    public function chat(string $role, array $messages, array $options = []): array
    {
        $toolFunctions = $this->getToolFunctions($role);

        if (!empty($toolFunctions)) {
            $options['tools'] = $toolFunctions;
            $options['tool_choice'] = 'auto';
        }

        // 推理模型默认关闭思考模式（输出更简洁）
        if (!isset($options['disable_thinking'])) {
            $options['disable_thinking'] = true;
        }

        return Client::instance()->chatWithFallback($messages, $options);
    }

    /**
     * 执行流式对话
     */
    public function chatStream(string $role, array $messages, array $options = []): \Generator
    {
        $toolFunctions = $this->getToolFunctions($role);

        if (!empty($toolFunctions)) {
            $options['tools'] = $toolFunctions;
            $options['tool_choice'] = 'auto';
        }

        // 推理模型默认关闭思考模式（输出更简洁）
        if (!isset($options['disable_thinking'])) {
            $options['disable_thinking'] = true;
        }

        yield from Client::instance()->chatStream($messages, $options);
    }

    /**
     * 工具调用结果转为消息
     */
    protected function toolResultToMessage(array $results): array
    {
        $messages = [];
        foreach ($results as $i => $result) {
            if ($result['success']) {
                $payload = ['success' => true];
                if (isset($result['data'])) $payload['data'] = $result['data'];
                if (isset($result['message'])) $payload['message'] = $result['message'];
                $content = json_encode($payload, JSON_UNESCAPED_UNICODE);
            } else {
                $content = json_encode([
                    'success' => false,
                    'error'   => $result['message'] ?? '未知错误',
                    'code'    => $result['code'] ?? 'unknown',
                    'confirm_required' => $result['confirm_required'] ?? false,
                ], JSON_UNESCAPED_UNICODE);
            }

            $messages[] = Types::tool("call_{$i}", $content);
        }
        return $messages;
    }

    /**
     * 记录 Agent 执行日志
     */
    protected function log(string $action, array $data = []): void
    {
        Logger::info("agent_{$this->getId()}_{$action}", '', $data);
    }
}
