/**
 * AG-UI 工具调用示例
 * 
 * 展示 Agent 如何调用工具并流式传输参数和结果
 * 
 * 参考文档: modules/events.md (行 938-1066)
 * 
 * 事件流:
 * 1. ToolCallStart - 工具调用开始
 * 2. ToolCallArgs (多次) - 流式传输参数
 * 3. ToolCallEnd - 参数传输完成
 * 4. ToolCallResult - 工具执行结果
 */

import {
  AbstractAgent,
  RunAgent,
  RunAgentInput,
  EventType,
  BaseEvent,
} from "@ag-ui/client"
import { Observable } from "rxjs"

/**
 * 工具定义示例
 */
interface Tool {
  name: string
  description: string
  parameters: Record<string, unknown>
}

const weatherTool: Tool = {
  name: "get_weather",
  description: "Get current weather for a location",
  parameters: {
    type: "object",
    properties: {
      location: {
        type: "string",
        description: "City name",
      },
      unit: {
        type: "string",
        enum: ["celsius", "fahrenheit"],
      },
    },
    required: ["location"],
  },
}

class ToolCallingAgent extends AbstractAgent {
  run(input: RunAgentInput): RunAgent {
    const { threadId, runId } = input

    return () =>
      new Observable<BaseEvent>((observer) => {
        observer.next({
          type: EventType.RUN_STARTED,
          threadId,
          runId,
        })

        // 模拟 Agent 分析用户请求后决定调用工具
        const toolCallId = `tool_${Date.now()}`
        const messageId = `msg_${Date.now()}`

        // 1. 发送文本消息说明
        observer.next({
          type: EventType.TEXT_MESSAGE_START,
          messageId,
          role: "assistant",
        })

        observer.next({
          type: EventType.TEXT_MESSAGE_CONTENT,
          messageId,
          delta: "Let me check the weather for you.",
        })

        observer.next({
          type: EventType.TEXT_MESSAGE_END,
          messageId,
        })

        // 2. 开始工具调用
        observer.next({
          type: EventType.TOOL_CALL_START,
          toolCallId,
          toolCallName: "get_weather",
          parentMessageId: messageId,
        })

        // 3. 流式传输参数（分块发送）
        observer.next({
          type: EventType.TOOL_CALL_ARGS,
          toolCallId,
          delta: '{"loc', // 参数片段 1
        })

        observer.next({
          type: EventType.TOOL_CALL_ARGS,
          toolCallId,
          delta: 'ation":', // 参数片段 2
        })

        observer.next({
          type: EventType.TOOL_CALL_ARGS,
          toolCallId,
          delta: ' "San Francisco"}', // 参数片段 3
        })

        // 4. 参数传输完成
        observer.next({
          type: EventType.TOOL_CALL_END,
          toolCallId,
        })

        // 5. 工具执行结果（模拟）
        setTimeout(() => {
          observer.next({
            type: EventType.TOOL_CALL_RESULT,
            toolCallId,
            content: JSON.stringify({
              location: "San Francisco",
              temperature: "18°C",
              condition: "Partly cloudy",
            }),
          })

          // 6. 基于工具结果的响应
          const responseMsgId = `msg_${Date.now()}_response`
          observer.next({
            type: EventType.TEXT_MESSAGE_START,
            messageId: responseMsgId,
            role: "assistant",
          })

          observer.next({
            type: EventType.TEXT_MESSAGE_CONTENT,
            messageId: responseMsgId,
            delta: "The current weather in San Francisco is 18°C and partly cloudy.",
          })

          observer.next({
            type: EventType.TEXT_MESSAGE_END,
            messageId: responseMsgId,
          })

          observer.next({
            type: EventType.RUN_FINISHED,
            threadId,
            runId,
          })

          observer.complete()
        }, 1000)
      })
  }
}

// 使用示例
const agent = new ToolCallingAgent()

agent
  .runAgent({
    runId: "run_tool_example",
    threadId: "thread_123",
    messages: [
      {
        id: "user_1",
        role: "user",
        content: "What's the weather in San Francisco?",
      },
    ],
    tools: [weatherTool as any],
    context: [],
  })
  .subscribe({
    next: (event) => {
      switch (event.type) {
        case EventType.TOOL_CALL_START:
          console.log(`[Tool Call] Starting: ${(event as any).toolCallName}`)
          break
        case EventType.TOOL_CALL_ARGS:
          process.stdout.write((event as any).delta)
          break
        case EventType.TOOL_CALL_END:
          console.log("\n[Tool Call] Arguments complete")
          break
        case EventType.TOOL_CALL_RESULT:
          console.log("[Tool Result]", (event as any).content)
          break
        default:
          console.log(`[${event.type}]`)
      }
    },
    complete: () => console.log("Tool call flow completed"),
  })

export { ToolCallingAgent, weatherTool }
