package eino

import (
	"context"
	"strings"
	"testing"
	"time"

	"github.com/cloudwego/eino/schema"
)

// 专家超时：卡死的专家应在 timeout 附近作为"观察"跳过（err=nil，不中断协调），
// 而非无限阻塞 lead。
func TestSpecialist_TimeoutSkips(t *testing.T) {
	o := newOrch(&fakeLLM{}, kbTool(nil), &fakeSink{}, &fakeExec{})
	st := &specialistTool{
		name:    "分析专家",
		tr:      o.tracer("t1"),
		timeout: 50 * time.Millisecond,
		info:    &schema.ToolInfo{Name: "分析专家"},
		run: func(ctx context.Context, _ string) (string, error) {
			<-ctx.Done() // 模拟卡死：直到超时被取消
			return "", ctx.Err()
		},
	}

	start := time.Now()
	out, err := st.InvokableRun(context.Background(), `{"brief":"干活"}`)
	elapsed := time.Since(start)

	if err != nil {
		t.Fatalf("专家超时应作为观察返回、err=nil（不中断协调），got err=%v", err)
	}
	if !strings.Contains(out, "超时") {
		t.Errorf("应返回超时观察，got %q", out)
	}
	if elapsed > 2*time.Second {
		t.Errorf("应在超时(50ms)附近返回，实际耗时 %v（疑似未生效）", elapsed)
	}
}

// 正常专家不受超时影响。
func TestSpecialist_NormalWithinTimeout(t *testing.T) {
	o := newOrch(&fakeLLM{}, kbTool(nil), &fakeSink{}, &fakeExec{})
	st := &specialistTool{
		name:    "快专家",
		tr:      o.tracer("t1"),
		timeout: time.Second,
		info:    &schema.ToolInfo{Name: "快专家"},
		run:     func(_ context.Context, brief string) (string, error) { return "结论:" + brief, nil },
	}
	out, err := st.InvokableRun(context.Background(), `{"brief":"分析X"}`)
	if err != nil || !strings.Contains(out, "结论:分析X") {
		t.Fatalf("正常专家应返回结论，got out=%q err=%v", out, err)
	}
}
