package eino

import (
	"context"
	"fmt"

	"github.com/cloudwego/eino/callbacks"
	"github.com/cloudwego/eino/components/model"
	"github.com/cloudwego/eino/components/tool"
	"github.com/cloudwego/eino/schema"
	ucallbacks "github.com/cloudwego/eino/utils/callbacks"
)

// composeTracer 把 Eino compose 运行时的回调（ChatModel / Tool 的 start/end/error）
// 翻译成我们现有的 ExecEvent 轨迹——可观测"归一"：用框架原生回调，而非各处手写 emit。
// node 为该次运行在"运行·观测"里的归属节点 id（如 agent:xxx）。
func composeTracer(tr *execTracer, node string) callbacks.Handler {
	return ucallbacks.NewHandlerHelper().
		ChatModel(&ucallbacks.ModelCallbackHandler{
			OnStart: func(ctx context.Context, _ *callbacks.RunInfo, in *model.CallbackInput) context.Context {
				tr.emit(node, "model", "start", "compose·ChatModel", inputMsgsPreview(in), 0)
				return ctx
			},
			OnEnd: func(ctx context.Context, _ *callbacks.RunInfo, out *model.CallbackOutput) context.Context {
				detail := ""
				if out != nil && out.Message != nil {
					detail = truncate(out.Message.Content, 120)
				}
				tr.emit(node, "model", "end", "compose·ChatModel", detail, 0)
				return ctx
			},
			OnEndWithStreamOutput: func(ctx context.Context, _ *callbacks.RunInfo, out *schema.StreamReader[*model.CallbackOutput]) context.Context {
				out.Close() // 仅观测：正文经主输出流消费，这里只标记结束
				tr.emit(node, "model", "end", "compose·ChatModel", "流式完成", 0)
				return ctx
			},
			OnError: func(ctx context.Context, _ *callbacks.RunInfo, err error) context.Context {
				tr.emit(node, "model", "error", "compose·ChatModel", err.Error(), 0)
				return ctx
			},
		}).
		Tool(&ucallbacks.ToolCallbackHandler{
			OnStart: func(ctx context.Context, _ *callbacks.RunInfo, in *tool.CallbackInput) context.Context {
				if in != nil {
					tr.emit(node, "tool", "start", "compose·工具", truncate(in.ArgumentsInJSON, 120), 0)
				}
				return ctx
			},
			OnEnd: func(ctx context.Context, _ *callbacks.RunInfo, out *tool.CallbackOutput) context.Context {
				if out != nil {
					tr.emit(node, "tool", "end", "compose·工具", truncate(out.Response, 160), 0)
				}
				return ctx
			},
			OnError: func(ctx context.Context, _ *callbacks.RunInfo, err error) context.Context {
				tr.emit(node, "tool", "error", "compose·工具", err.Error(), 0)
				return ctx
			},
		}).
		Handler()
}

func inputMsgsPreview(in *model.CallbackInput) string {
	if in == nil {
		return ""
	}
	return fmt.Sprintf("%d 条消息", len(in.Messages))
}
