package agent

import (
	"path/filepath"
	"runtime"
	"testing"
)

// TestPathWithin 验证路径越界校验：read_file / write_file / run_coop 的 blackboard
// 都依赖该函数拦截指向项目根目录之外的路径，是核心安全边界。
func TestPathWithin(t *testing.T) {
	var parent string
	if runtime.GOOS == "windows" {
		parent = `e:\proj`
	} else {
		parent = "/proj"
	}

	cases := []struct {
		name   string
		child  string
		expect bool
	}{
		{"自身", parent, true},
		{"直接子文件", filepath.Join(parent, "a.txt"), true},
		{"嵌套子目录", filepath.Join(parent, "sub", "deep", "f.txt"), true},
		{"上级目录", filepath.Join(parent, "..", "secret"), false},
		{"同级兄弟目录", filepath.Join(filepath.Dir(parent), "other"), false},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			if got := pathWithin(tc.child, parent); got != tc.expect {
				t.Fatalf("pathWithin(%q, %q) = %v, want %v", tc.child, parent, got, tc.expect)
			}
		})
	}
}

// TestMergeToolCall 验证 SSE 流式 tool_call 增量合并：
// 跨多个 chunk 按 index 聚合 id / name / arguments，是 LLM 工具调用协议正确性的关键。
func TestMergeToolCall(t *testing.T) {
	var calls []ToolCall
	// 第一个 chunk：声明 index 0 的调用（id + name）
	calls = mergeToolCall(calls, ToolCallDelta{Index: 0, ID: "call_1", Name: "run_bash"})
	// 同一调用的参数分片到达
	calls = mergeToolCall(calls, ToolCallDelta{Index: 0, ArgumentsDelta: `{"comm`})
	calls = mergeToolCall(calls, ToolCallDelta{Index: 0, ArgumentsDelta: `and":"ls"}`})

	if len(calls) != 1 {
		t.Fatalf("应合并为 1 个调用，got %d", len(calls))
	}
	c := calls[0]
	if c.ID != "call_1" || c.Function.Name != "run_bash" {
		t.Fatalf("id/name 不匹配: %+v", c)
	}
	if c.Function.Arguments != `{"command":"ls"}` {
		t.Fatalf("arguments 拼接错误: %q", c.Function.Arguments)
	}

	// 第二个调用在 index 1
	calls = mergeToolCall(calls, ToolCallDelta{Index: 1, ID: "call_2", Name: "read_file"})
	calls = mergeToolCall(calls, ToolCallDelta{Index: 1, ArgumentsDelta: `{"path":"a"}`})
	if len(calls) != 2 {
		t.Fatalf("应有 2 个调用，got %d", len(calls))
	}
	if calls[1].Function.Name != "read_file" {
		t.Fatalf("第二个调用名错误: %+v", calls[1])
	}

	// index 为负时回退为追加新调用
	prev := len(calls)
	calls = mergeToolCall(calls, ToolCallDelta{Index: -1, ID: "call_3", Name: "list_directory"})
	if len(calls) != prev+1 {
		t.Fatalf("负 index 应追加新调用，got %d", len(calls))
	}
}
