<?php

namespace XZD\AI\V5\Agents;

use XZD\AI\V5\AI\Types;
use XZD\AI\V5\Core\Logger;

/**
 * AgentLoop — ReAct 对话循环 (Thought → Tool → Observe → Response)
 *
 * 职责:
 * - 调用 Agent + AI 获取回复
 * - 如果 AI 返回 tool_calls，通过 ActionDispatcher 执行
 * - 将工具结果反馈给 AI 继续对话
 * - 循环直到 AI 不再调用工具，或达到最大轮次
 */
class AgentLoop
{
    private BaseAgent $agent;
    private ActionDispatcher $dispatcher;
    private SessionManager $sessionManager;
    private int $maxTurns;

    public function __construct(BaseAgent $agent, ActionDispatcher $dispatcher, int $maxTurns = 5)
    {
        $this->agent = $agent;
        $this->dispatcher = $dispatcher;
        $this->sessionManager = new SessionManager();
        $this->maxTurns = $maxTurns;
    }

    /**
     * 执行完整的 ReAct 循环
     *
     * @return array ['content'=>'...','tool_calls'=>[...],'turns'=>N,'messages'=>[...]]
     */
    public function run(string $sessionKey, string $userMessage, string $role, int $userId): array
    {
        $systemPrompt = $this->agent->getSystemPrompt($role, $userId);
        $history = $this->sessionManager->getRecentMessages($sessionKey, 20);

        $messages = array_merge(
            [Types::system($systemPrompt)],
            $history,
            [Types::user($userMessage)]
        );

        $finalContent = '';
        $allToolCalls = [];
        $turn = 0;

        for ($turn = 0; $turn < $this->maxTurns; $turn++) {
            // Step 1: Thought — AI 思考并决定是否调用工具
            $response = $this->agent->chat($role, $messages);
            $content = $response['content'] ?? '';
            $toolCalls = $response['tool_calls'] ?? null;

            // AI 直接回复文本（不再调用工具）
            if (empty($toolCalls)) {
                $finalContent = $content;
                // 保存助手回复
                $this->sessionManager->addMessage($sessionKey, 'assistant', $finalContent, [
                    'model'        => $response['model'] ?? '',
                    'input_tokens'  => $response['input_tokens'] ?? 0,
                    'output_tokens' => $response['output_tokens'] ?? 0,
                ]);

                // 更新会话标题和统计
                $this->sessionManager->touchSession($sessionKey, [
                    'title'  => mb_substr($userMessage, 0, 50),
                    'model'  => $response['model'] ?? '',
                    'tokens' => ($response['input_tokens'] ?? 0) + ($response['output_tokens'] ?? 0),
                ]);

                break;
            }

            $allToolCalls[] = ['turn' => $turn, 'calls' => $toolCalls];

            // Step 2: 将助手回复加入消息历史（含全部 tool_calls 供 AI 处理）
            $messages[] = [
                'role'       => 'assistant',
                'content'    => $content,
                'tool_calls' => $toolCalls,
            ];

            // Step 3: Tool — 执行工具调用
            $toolResults = [];
            $pendingConfirms = []; // 收集需要确认的工具
            $executedToolCalls = []; // 实际执行了的工具调用
            foreach ($toolCalls as $i => $tc) {
                $funcName = $tc['function']['name'] ?? '';
                $funcArgs = json_decode($tc['function']['arguments'] ?? '{}', true) ?: [];
                $tcId = $tc['id'] ?? "call_{$turn}_{$i}";

                Logger::info('agent_loop_tool', "Turn {$turn}: {$funcName}", [
                    'session' => $sessionKey,
                    'args'    => $funcArgs,
                ]);

                $result = $this->dispatcher->dispatch($funcName, $funcArgs, $userId, $sessionKey);

                // 记录操作日志（统一审计）
                $tool = \XZD\AI\V5\Tools\ToolRegistry::instance()->get($funcName);
                Logger::operation([
                    'tool_id'     => $funcName,
                    'tool_name'   => $tool ? $tool->name : $funcName,
                    'category'    => $tool ? $tool->category : 'unknown',
                    'params'      => $funcArgs,
                    'result'      => $result,
                    'status'      => $result['success'] ? 'success' : 'failed',
                    'error_message' => $result['success'] ? null : ($result['message'] ?? ''),
                    'user_id'     => $userId,
                    'session_key' => $sessionKey,
                ]);

                // 如果操作需要确认，收集到待确认列表
                if (!empty($result['confirm_required'])) {
                    $pendingConfirms[] = [
                        'tool_call'      => $tc,
                        'confirm_key'    => $result['confirm_key'] ?? '',
                        'confirm_message'=> $result['confirm_message'] ?? '请确认操作',
                        'confirm_detail' => $result['confirm_detail'] ?? '',
                    ];
                    continue; // 跳过此工具的后续处理，等待确认
                }

                $executedToolCalls[] = $tc;

                // Step 4: Observe — 工具结果加入消息
                if ($result['success']) {
                    $payload = ['success' => true];
                    if (isset($result['data'])) $payload['data'] = $result['data'];
                    if (isset($result['message'])) $payload['message'] = $result['message'];
                    $resultContent = json_encode($payload, JSON_UNESCAPED_UNICODE);
                } else {
                    $resultContent = json_encode([
                        'success' => false,
                        'error'   => $result['message'] ?? '未知错误',
                        'code'    => $result['code'] ?? 'unknown',
                        'confirm_required' => $result['confirm_required'] ?? false,
                    ], JSON_UNESCAPED_UNICODE);
                }

                $messages[] = Types::tool($tcId, $resultContent);
                $toolResults[] = [
                    'tool_call_id' => $tcId,
                    'result'       => $result,
                ];

                // 保存工具结果
                $this->sessionManager->addMessage($sessionKey, 'tool', $resultContent, [
                    'tool_call_id' => $tcId,
                ]);
            }

            // Step 5: 保存助手消息（仅含已执行工具的 tool_calls，待确认工具不记入）
            $assistantMsgId = $this->sessionManager->addMessage($sessionKey, 'assistant', $content, [
                'tool_calls'    => !empty($executedToolCalls) ? $executedToolCalls : null,
                'model'         => $response['model'] ?? '',
                'input_tokens'  => $response['input_tokens'] ?? 0,
                'output_tokens' => $response['output_tokens'] ?? 0,
            ]);

            // 如果有待确认的工具，一次性返回所有确认请求
            if (!empty($pendingConfirms)) {
                $confirmKeys = array_column($pendingConfirms, 'confirm_key');
                $confirmMessages = array_column($pendingConfirms, 'confirm_message');
                $confirmDetails = array_column($pendingConfirms, 'confirm_detail');
                $pendingCalls = array_column($pendingConfirms, 'tool_call');

                return [
                    'content'          => implode("\n", $confirmMessages),
                    'confirm_required' => true,
                    'confirm_keys'     => $confirmKeys,
                    'confirm_key'      => $confirmKeys[0], // 向后兼容
                    'confirm_message'  => implode("\n\n", $confirmMessages),
                    'confirm_detail'   => implode("\n---\n", $confirmDetails),
                    'pending_tool_calls' => $pendingCalls,
                    'tool_calls'       => $allToolCalls,
                    'turns'            => $turn + 1,
                ];
            }

            // 如果没有累积到最终内容，继续下一轮
            if ($turn === $this->maxTurns - 1) {
                $finalContent = $content ?: '处理完成，但达到了最大执行轮次。';
            }
        }

        // 更新会话统计
        if ($turn > 0) {
            $this->sessionManager->touchSession($sessionKey, [
                'title'  => mb_substr($userMessage, 0, 50),
            ]);
        }

        return [
            'content'    => $finalContent ?: '处理完成',
            'tool_calls' => $allToolCalls,
            'turns'      => $turn,
            'messages'   => $messages,
        ];
    }

    /**
     * 仅执行工具调用（不重新调用 AI，用于确认后恢复执行）
     *
     * @param array $confirmedToolCalls 用户确认后的工具调用
     * @param int   $userId
     * @param string $sessionKey
     * @return array
     */
    public function executeToolsOnly(array $confirmedToolCalls, int $userId, string $sessionKey): array
    {
        $toolResults = [];
        foreach ($confirmedToolCalls as $i => $tc) {
            $funcName = $tc['function']['name'] ?? '';
            $funcArgs = json_decode($tc['function']['arguments'] ?? '{}', true) ?: [];
            $tcId = $tc['id'] ?? "confirm_call_{$i}";

            $result = $this->dispatcher->dispatch($funcName, $funcArgs, $userId, $sessionKey);
            $toolResults[] = [
                'tool_call_id' => $tcId,
                'result'       => $result,
            ];
        }
        return $toolResults;
    }

    /**
     * 流式执行 ReAct 循环
     */
    public function runStream(string $sessionKey, string $userMessage, string $role, int $userId): \Generator
    {
        $systemPrompt = $this->agent->getSystemPrompt($role, $userId);
        $history = $this->sessionManager->getRecentMessages($sessionKey, 20);

        $messages = array_merge(
            [Types::system($systemPrompt)],
            $history,
            [Types::user($userMessage)]
        );

        // 保存用户消息
        $this->sessionManager->addMessage($sessionKey, 'user', $userMessage);

        $allToolCalls = [];

        for ($turn = 0; $turn < $this->maxTurns; $turn++) {
            $fullContent = '';
            $currentToolCalls = [];

            // 流式获取 AI 回复
            foreach ($this->agent->chatStream($role, $messages) as $chunk) {
                if (isset($chunk['error'])) {
                    yield ['delta' => '', 'type' => 'error', 'done' => true, 'error' => $chunk['error']];
                    return;
                }

                $delta = $chunk['delta'] ?? '';
                $fullContent .= $delta;

                // 流式输出文本
                if (!empty($delta)) {
                    yield [
                        'delta'    => $delta,
                        'type'     => 'text',
                        'done'     => false,
                        'turn'     => $turn,
                    ];
                }

                // 收集工具调用
                if (!empty($chunk['tool_call'])) {
                    $currentToolCalls = $chunk['tool_call'];
                }

                if ($chunk['done'] ?? false) {
                    break;
                }
            }

            // ★ 过滤掉流式返回的不完整 tool_call（空函数名）
            $currentToolCalls = array_values(array_filter($currentToolCalls, function ($tc) {
                return !empty($tc['function']['name'] ?? '');
            }));

            // 没有有效工具调用 → 对话结束
            if (empty($currentToolCalls)) {
                $finalContent = $fullContent ?: '处理完成';
                $this->sessionManager->addMessage($sessionKey, 'assistant', $finalContent);
                yield ['delta' => $finalContent, 'type' => 'text', 'done' => false, 'turn' => $turn];
                yield ['delta' => '', 'type' => 'done', 'done' => true, 'turn' => $turn];
                return;
            }

            // 有工具调用 → 执行
            $allToolCalls[] = ['turn' => $turn, 'calls' => $currentToolCalls];

            // 通知前端正在执行工具
            foreach ($currentToolCalls as $tc) {
                $rawName = $tc['function']['name'] ?? '';
                $tool = \XZD\AI\V5\Tools\ToolRegistry::instance()->get($rawName);
                $displayName = $tool ? $tool->name : $rawName;
                $toolAction = $tool ? $tool->description : '';
                yield [
                    'delta'         => '',
                    'type'          => 'tool_exec',
                    'done'          => false,
                    'turn'          => $turn,
                    'tool_name'     => $displayName,
                    'tool_id'       => $rawName,
                    'tool_action'   => mb_substr($toolAction, 0, 80),
                    'tool_call_id'  => $tc['id'] ?? '',
                ];
            }

            // 加入助手消息（含全部 tool_calls 供 AI 多轮处理）
            $messages[] = [
                'role'       => 'assistant',
                'content'    => $fullContent,
                'tool_calls' => $currentToolCalls,
            ];

            // 执行工具 + 加入结果
            $streamPendingConfirms = [];
            $streamExecutedCalls = [];
            foreach ($currentToolCalls as $tc) {
                $funcName = $tc['function']['name'] ?? '';
                $funcArgs = json_decode($tc['function']['arguments'] ?? '{}', true) ?: [];
                $tcId = $tc['id'] ?? '';

                // 通知前端工具开始执行（长耗时工具给用户反馈）
                $toolObj = \XZD\AI\V5\Tools\ToolRegistry::instance()->get($funcName);
                yield [
                    'delta'         => '',
                    'type'          => 'tool_running',
                    'done'          => false,
                    'turn'          => $turn,
                    'tool_name'     => $toolObj ? $toolObj->name : $funcName,
                    'tool_id'       => $funcName,
                    'tool_call_id'  => $tcId,
                    'message'       => '正在执行 ' . ($toolObj ? $toolObj->name : $funcName) . '...',
                ];

                $result = $this->dispatcher->dispatch($funcName, $funcArgs, $userId, $sessionKey);

                // 如果需要确认，收集到待确认列表
                if (!empty($result['confirm_required'])) {
                    $streamPendingConfirms[] = [
                        'tool_call'       => $tc,
                        'confirm_key'     => $result['confirm_key'] ?? '',
                        'confirm_message' => $result['confirm_message'] ?? '请确认操作',
                        'confirm_detail'  => $result['confirm_detail'] ?? '',
                    ];
                    // 发送工具结果（待确认状态）
                    yield [
                        'delta'         => json_encode($result, JSON_UNESCAPED_UNICODE),
                        'type'          => 'tool_result',
                        'done'          => false,
                        'turn'          => $turn,
                        'tool_name'     => $funcName,
                        'tool_call_id'  => $tcId,
                        'tool_success'  => false,
                        'confirm_required' => true,
                    ];
                    continue;
                }

                $streamExecutedCalls[] = $tc;

                $resultContent = $result['success']
                    ? json_encode($result['data'] ?? $result['message'] ?? 'ok', JSON_UNESCAPED_UNICODE)
                    : "错误: " . ($result['message'] ?? '未知错误');

                $messages[] = Types::tool($tcId, $resultContent);
                $this->sessionManager->addMessage($sessionKey, 'tool', $resultContent, [
                    'tool_call_id' => $tcId,
                ]);

                // 记录操作日志
                $tool = \XZD\AI\V5\Tools\ToolRegistry::instance()->get($funcName);
                Logger::operation([
                    'tool_id'     => $funcName,
                    'tool_name'   => $tool ? $tool->name : $funcName,
                    'category'    => $tool ? $tool->category : 'unknown',
                    'params'      => $funcArgs,
                    'result'      => $result,
                    'status'      => $result['success'] ? 'success' : 'failed',
                    'error_message' => $result['success'] ? null : ($result['message'] ?? ''),
                    'user_id'     => $userId,
                    'session_key' => $sessionKey,
                ]);

                // 检测生成图片的工具结果，提取图片 URL 供前端直接显示
                $imageUrl = null;
                if (!empty($result['success']) && !empty($result['data'])) {
                    $d = $result['data'];
                    if (!empty($d['url']) && filter_var($d['url'], FILTER_VALIDATE_URL)) {
                        $imageUrl = $d['url'];
                    } elseif (!empty($d['image_url']) && filter_var($d['image_url'], FILTER_VALIDATE_URL)) {
                        $imageUrl = $d['image_url'];
                    } elseif (is_string($d) && preg_match('/^https?:\/\/.*\.(png|jpg|jpeg|gif|webp)/i', $d)) {
                        $imageUrl = $d;
                    }
                }

                // 发送工具结果给前端
                yield [
                    'delta'         => json_encode($result, JSON_UNESCAPED_UNICODE),
                    'type'          => 'tool_result',
                    'done'          => false,
                    'turn'          => $turn,
                    'tool_name'     => $funcName,
                    'tool_call_id'  => $tcId,
                    'tool_success'  => $result['success'],
                    'image_url'     => $imageUrl,  // 图片直显 URL
                ];
            }

            // 保存助手消息（仅含已执行工具的 tool_calls，待确认工具不记入）
            $this->sessionManager->addMessage($sessionKey, 'assistant', $fullContent, [
                'tool_calls' => !empty($streamExecutedCalls) ? $streamExecutedCalls : null,
            ]);

            // 如果有待确认的工具，一次性返回所有确认请求
            if (!empty($streamPendingConfirms)) {
                $confirmKeys = array_column($streamPendingConfirms, 'confirm_key');
                $confirmMessages = array_column($streamPendingConfirms, 'confirm_message');
                $confirmDetails = array_column($streamPendingConfirms, 'confirm_detail');
                yield [
                    'delta'              => implode("\n\n", $confirmMessages),
                    'type'               => 'confirm_required',
                    'done'               => true,
                    'confirm_keys'       => $confirmKeys,
                    'confirm_key'        => $confirmKeys[0],
                    'confirm_message'    => implode("\n\n", $confirmMessages),
                    'confirm_detail'     => implode("\n---\n", $confirmDetails),
                ];
                return;
            }
        }

        yield ['delta' => '', 'type' => 'done', 'done' => true];
    }
}
