/**
 * Agent Loop — LLM 输出解析器
 *
 * 使用 Zod Schema 定义 ReAct 输出格式。
 * 优先使用 Structured Output / Tool Calling，降级为正则解析。
 *
 * @see docs/生产级通用 AI Agent 智能体桌面应用：完整设计与构建指南.html — 第四章
 */

import { z } from 'zod';
import type { Thought } from './types';
import type { MetonaToolCall } from '../types';

/** 思考内容 Schema */
export const ThoughtSchema = z.object({
  type: z.literal('thought'),
  content: z.string().describe('当前的推理思考过程'),
  needs_tool: z.boolean().describe('是否需要调用工具'),
});

/** 工具调用 Schema */
export const ToolCallSchema = z.object({
  type: z.literal('tool_call'),
  tool_name: z.string().describe('要调用的工具名称'),
  args: z.record(z.unknown()).describe('工具参数'),
  reasoning: z.string().describe('为什么选择这个工具'),
});

/** 最终答案 Schema */
export const FinalAnswerSchema = z.object({
  type: z.literal('final_answer'),
  answer: z.string().describe('最终答案内容'),
  confidence: z.number().min(0).max(1).describe('答案置信度'),
  summary: z.string().describe('简要总结'),
});

/** ReAct 步骤联合类型 */
export const ReActStepSchema = z.discriminatedUnion('type', [
  ThoughtSchema,
  ToolCallSchema,
  FinalAnswerSchema,
]);

/**
 * LLM 输出解析器
 */
export function parseLLMOutput(rawText: string, iteration: number): {
  thought?: Thought;
  toolCalls?: MetonaToolCall[];
} {
  // 尝试 JSON 解析（Structured Output 模式）
  try {
    const jsonStart = rawText.indexOf('{');
    const jsonEnd = rawText.lastIndexOf('}');
    if (jsonStart !== -1 && jsonEnd !== -1) {
      const jsonStr = rawText.slice(jsonStart, jsonEnd + 1);
      const parsed = JSON.parse(jsonStr);
      const validated = ReActStepSchema.safeParse(parsed);

      if (validated.success) {
        const data = validated.data;
        switch (data.type) {
          case 'thought':
            return {
              thought: {
                id: `thought-${iteration}`,
                content: data.content,
                timestamp: Date.now(),
                iteration,
              },
            };
          case 'tool_call':
            return {
              toolCalls: [{
                id: `call-${iteration}-${Date.now()}`,
                name: data.tool_name,
                args: data.args as Record<string, unknown>,
                timestamp: Date.now(),
                iteration,
              }],
            };
          case 'final_answer':
            return {
              thought: {
                id: `answer-${iteration}`,
                content: `[FINAL ANSWER]\n${data.answer}\n\nConfidence: ${data.confidence}\nSummary: ${data.summary}`,
                timestamp: Date.now(),
                iteration,
              },
            };
        }
      }
    }
  } catch {
    // JSON 解析失败，降级到正则提取
  }

  // 降级：正则提取
  return parseWithRegex(rawText, iteration);
}

/** 正则降级解析 */
function parseWithRegex(text: string, iteration: number): {
  thought?: Thought;
  toolCalls?: MetonaToolCall[];
} {
  const result: { thought?: Thought; toolCalls?: MetonaToolCall[] } = {};

  const thoughtMatch = text.match(/Thought:\s*([\s\S]*?)(?=Action:|$)/i);
  if (thoughtMatch) {
    result.thought = {
      id: `thought-${iteration}`,
      content: thoughtMatch[1].trim(),
      timestamp: Date.now(),
      iteration,
    };
  }

  const actionMatch = text.match(/Action:\s*(\w+)\s*\n\s*Action Input:\s*({[\s\S]*?})\s*(?=\n\n|Observation:|$)/i);
  if (actionMatch) {
    try {
      result.toolCalls = [{
        id: `call-${iteration}-${Date.now()}`,
        name: actionMatch[1].trim(),
        args: JSON.parse(actionMatch[2]),
        timestamp: Date.now(),
        iteration,
      }];
    } catch {
      // 参数 JSON 解析失败
    }
  }

  return result;
}
