package openai

import (
	"encoding/json"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"testing"

	"iop/packages/go/config"
)

func TestWorkspaceToolBindingContract(t *testing.T) {
	structured := workspaceAlternative("structured", "write_file", false, true)
	command := workspaceAlternative("command", "run_workspace", true, false)
	openAITools := []any{openAIChatTool("write_file", structuredSchema()), unrelatedTool()}
	anthropicTools := []any{anthropicWorkspaceTool("write_file", structuredSchema()), unrelatedTool()}

	t.Run("normalizes actual OpenAI and Anthropic definitions", func(t *testing.T) {
		openAIBinding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, openAITools)
		if err != nil {
			t.Fatalf("compile OpenAI tool: %v", err)
		}
		anthropicBinding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, anthropicTools)
		if err != nil {
			t.Fatalf("compile Anthropic tool: %v", err)
		}
		if openAIBinding.alternativeName != "structured" || anthropicBinding.alternativeName != "structured" {
			t.Fatalf("unexpected selected alternatives: %q, %q", openAIBinding.alternativeName, anthropicBinding.alternativeName)
		}
		if openAIBinding.fingerprint != anthropicBinding.fingerprint {
			t.Fatalf("normalized endpoint shapes must fingerprint identically: %s != %s", openAIBinding.fingerprint, anthropicBinding.fingerprint)
		}
	})

	t.Run("normalizes native decoded Anthropic tool", func(t *testing.T) {
		rawSchema, err := json.Marshal(structuredSchema())
		if err != nil {
			t.Fatalf("marshal native schema: %v", err)
		}
		nativeBinding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, []anthropicTool{
			anthropicTool{Name: "write_file", Description: "workspace tool", InputSchema: rawSchema},
		})
		if err != nil {
			t.Fatalf("compile native Anthropic tool: %v", err)
		}
		openAIBinding := mustBinding(t, structured, []any{openAIChatTool("write_file", structuredSchema())})
		if nativeBinding.fingerprint != openAIBinding.fingerprint {
			t.Fatalf("native Anthropic fingerprint = %s, want %s", nativeBinding.fingerprint, openAIBinding.fingerprint)
		}
	})

	t.Run("rejects unsupported command placeholders and missing write content", func(t *testing.T) {
		for name, argv := range map[string][]any{
			"missing content":          {"write", "{path}"},
			"duplicate content":        {"write", "{path}", "{content}", "{content}"},
			"embedded placeholder":     {"write", "--path={path}", "{content}"},
			"unknown placeholder":      {"write", "{path}", "{unsupported}", "{content}"},
			"missing path placeholder": {"write", "{content}"},
		} {
			t.Run(name, func(t *testing.T) {
				invalid := workspaceAlternative("invalid-command", "run_workspace", true, true)
				invalid.Operations["write"] = config.ExecutionWorkspaceOperation{
					ToolName: "run_workspace", SchemaMatcher: map[string]any{"type": "object"},
					ArgumentMap:   map[string]any{"path": "path", "content": "content", "command": "command", "argv": argv},
					ResultMatcher: successMatcher(), CreatesParents: true,
				}
				if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{invalid}, []any{openAIChatTool("run_workspace", commandSchema())}); err == nil {
					t.Fatal("invalid command template unexpectedly compiled")
				}
			})
		}
	})

	t.Run("uses configured order and rejects name heuristics", func(t *testing.T) {
		fallback, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{command, structured}, openAITools)
		if err != nil {
			t.Fatalf("compile fallback: %v", err)
		}
		if fallback.alternativeName != "structured" {
			t.Fatalf("expected configured second alternative, got %q", fallback.alternativeName)
		}
		if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, []any{unrelatedTool()}); err == nil {
			t.Fatal("unrelated get_weather tool must not bind by lexical role inference")
		}
	})

	t.Run("rejects missing tools, schema mismatch, and incomplete parent contract", func(t *testing.T) {
		missing := workspaceAlternative("missing", "absent_tool", true, true)
		if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{missing}, openAITools); err == nil {
			t.Fatal("missing configured tool unexpectedly bound")
		}
		mismatched := workspaceAlternative("mismatched", "write_file", true, true)
		mismatched.Operations["write"] = config.ExecutionWorkspaceOperation{
			ToolName:       "write_file",
			SchemaMatcher:  map[string]any{"type": "object", "properties": map[string]any{"bytes": map[string]any{"type": "number"}}},
			ArgumentMap:    map[string]any{"path": "path", "content": "content"},
			ResultMatcher:  successMatcher(),
			CreatesParents: true,
		}
		if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{mismatched}, openAITools); err == nil {
			t.Fatal("schema-mismatched configured tool unexpectedly bound")
		}
		noPrepare := workspaceAlternative("no-prepare", "write_file", false, false)
		delete(noPrepare.Operations, "prepare")
		if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{noPrepare}, openAITools); err == nil {
			t.Fatal("write without parent capability or prepare unexpectedly bound")
		}
	})

	t.Run("copies full contract into a stable fingerprint", func(t *testing.T) {
		binding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, openAITools)
		if err != nil {
			t.Fatalf("compile binding: %v", err)
		}
		before := binding.fingerprint
		structured.Operations["write"] = config.ExecutionWorkspaceOperation{ToolName: "changed"}
		if binding.fingerprint != before || binding.operation(opKindWrite).toolName != "write_file" {
			t.Fatal("binding retained mutable config state")
		}
		openAITools[0].(map[string]any)["function"].(map[string]any)["parameters"].(map[string]any)["properties"].(map[string]any)["path"] = map[string]any{"type": "number"}
		if binding.operation(opKindWrite).normalizedSchema.properties["path"].(map[string]any)["type"] != "string" {
			t.Fatal("binding retained mutable request tool schema")
		}
		withDifferentReceipt := workspaceAlternative("structured", "write_file", false, true)
		withDifferentReceipt.Operations["write"] = config.ExecutionWorkspaceOperation{
			ToolName: "write_file", SchemaMatcher: map[string]any{"type": "object"},
			ArgumentMap:   map[string]any{"path": "path", "content": "content"},
			ResultMatcher: map[string]any{"status": "success", "result": map[string]any{"saved": true}}, CreatesParents: true,
		}
		changed, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{withDifferentReceipt}, openAITools)
		if err != nil {
			t.Fatalf("compile changed receipt binding: %v", err)
		}
		if before == changed.fingerprint {
			t.Fatal("fingerprint omitted configured result contract")
		}
	})
}

func TestWorkspaceContainmentGuard(t *testing.T) {
	writeCall := func(path string) normalizedToolCall {
		return normalizedToolCall{ID: "guard-call", Name: "write_file", Arguments: map[string]any{"path": path, "content": "x"}}
	}

	t.Run("parent-capable write admits fresh nested parents", func(t *testing.T) {
		binding := mustBinding(t, workspaceAlternative("parents", "write_file", false, true), []any{openAIChatTool("write_file", structuredSchema())})
		payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall(".iop/job/request-1/plan.md"))
		if err != nil {
			t.Fatalf("encode workspace call: %v", err)
		}
		if err := evaluateContainmentGuard(t.TempDir(), payload.containmentGuard); err != nil {
			t.Fatalf("parent-capable guard rejected a fresh nested path: %v", err)
		}
	})

	t.Run("write without parent capability requires immediate parent", func(t *testing.T) {
		binding := mustBinding(t, workspaceAlternative("prepare-required", "write_file", false, false), []any{openAIChatTool("write_file", structuredSchema())})
		payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall(".iop/job/request-2/plan.md"))
		if err != nil {
			t.Fatalf("encode workspace call: %v", err)
		}
		if err := evaluateContainmentGuard(t.TempDir(), payload.containmentGuard); err == nil {
			t.Fatal("non-parent-capable guard accepted a missing immediate parent")
		}
	})

	t.Run("root workspace admits existing relative target", func(t *testing.T) {
		binding := mustBinding(t, workspaceAlternative("parents", "write_file", false, true), []any{openAIChatTool("write_file", structuredSchema())})
		payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall("tmp"))
		if err != nil {
			t.Fatalf("encode workspace call: %v", err)
		}
		if err := evaluateContainmentGuard("/", payload.containmentGuard); err != nil {
			t.Fatalf("root workspace guard rejected existing relative target: %v", err)
		}
	})

	t.Run("root workspace admits non-parent-capable target with existing immediate parent", func(t *testing.T) {
		binding := mustBinding(t, workspaceAlternative("prepare-required", "write_file", false, false), []any{openAIChatTool("write_file", structuredSchema())})
		payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall("tmp/iop_root_test_file.txt"))
		if err != nil {
			t.Fatalf("encode workspace call: %v", err)
		}
		if err := evaluateContainmentGuard("/", payload.containmentGuard); err != nil {
			t.Fatalf("root workspace guard rejected non-parent-capable target with existing parent: %v", err)
		}
	})

	for name, setup := range map[string]func(t *testing.T, root, outside string){
		"final symlink": func(t *testing.T, root, outside string) {
			t.Helper()
			if err := os.MkdirAll(filepath.Join(root, ".iop", "job", "request-3"), 0o755); err != nil {
				t.Fatalf("create workspace path: %v", err)
			}
			if err := os.WriteFile(filepath.Join(outside, "target.md"), []byte("outside"), 0o600); err != nil {
				t.Fatalf("create outside target: %v", err)
			}
			if err := os.Symlink(filepath.Join(outside, "target.md"), filepath.Join(root, ".iop", "job", "request-3", "plan.md")); err != nil {
				t.Fatalf("create final symlink: %v", err)
			}
		},
		"ancestor symlink": func(t *testing.T, root, outside string) {
			t.Helper()
			if err := os.Symlink(outside, filepath.Join(root, ".iop")); err != nil {
				t.Fatalf("create ancestor symlink: %v", err)
			}
		},
	} {
		t.Run(name+" escapes workspace", func(t *testing.T) {
			root := t.TempDir()
			outside := t.TempDir()
			setup(t, root, outside)
			binding := mustBinding(t, workspaceAlternative("parents", "write_file", false, true), []any{openAIChatTool("write_file", structuredSchema())})
			payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall(".iop/job/request-3/plan.md"))
			if err != nil {
				t.Fatalf("encode workspace call: %v", err)
			}
			if err := evaluateContainmentGuard(root, payload.containmentGuard); err == nil {
				t.Fatal("symlink escape was accepted")
			}
		})
	}
}

// evaluateContainmentGuard executes only the generated guard against a
// temporary workspace fixture. It never invokes a caller workspace command.
func evaluateContainmentGuard(root, guard string) error {
	cmd := exec.Command("sh", "-c", guard)
	cmd.Env = append(os.Environ(), "IOP_WORKSPACE_CWD="+root)
	return cmd.Run()
}

func TestWorkspaceCommandEncodingAndGuards(t *testing.T) {
	structured := workspaceAlternative("structured", "write_file", false, true)
	command := workspaceAlternative("command", "run_workspace", true, false)

	t.Run("structured payload preserves typed values and identities", func(t *testing.T) {
		binding := mustBinding(t, structured, []any{openAIChatTool("write_file", structuredSchema())})
		content := map[string]any{"lines": []any{"first", 2, true}, "nested": map[string]any{"raw": "' $HOME"}}
		payload, err := encodeWorkspaceCall(binding, opKindWrite, normalizedToolCall{
			ID: "public-1", ProviderCallID: "provider-1", Name: "write_file",
			Arguments: map[string]any{"path": ".iop/job/r1/plan.md", "content": content, "ignored": "must not pass"},
		})
		if err != nil {
			t.Fatalf("encode structured call: %v", err)
		}
		if payload.publicCallID != "public-1" || payload.providerCallID != "provider-1" {
			t.Fatalf("call identities lost: %#v", payload)
		}
		if !reflect.DeepEqual(payload.structuredArgs["content"], content) {
			t.Fatalf("structured content changed: %#v", payload.structuredArgs["content"])
		}
		if _, present := payload.structuredArgs["ignored"]; present {
			t.Fatal("unmapped structured argument escaped the configured contract")
		}
	})

	t.Run("command mapping has fixed positions and shell-safe output", func(t *testing.T) {
		binding := mustBinding(t, command, []any{openAIChatTool("run_workspace", commandSchema())})
		call := normalizedToolCall{ID: "public-2", Name: "run_workspace", Arguments: map[string]any{"path": ".iop/job/r2/review.md", "content": "hello 'world'"}}
		first, err := encodeWorkspaceCall(binding, opKindWrite, call)
		if err != nil {
			t.Fatalf("encode command call: %v", err)
		}
		second, err := encodeWorkspaceCall(binding, opKindWrite, call)
		if err != nil || first.commandString != second.commandString {
			t.Fatalf("command encoding is not deterministic: %q / %q (%v)", first.commandString, second.commandString, err)
		}
		wantArgv := []string{"write", ".iop/job/r2/review.md", "hello 'world'"}
		if !reflect.DeepEqual(first.commandArgv, wantArgv) {
			t.Fatalf("command argv = %#v, want %#v", first.commandArgv, wantArgv)
		}
		if !strings.Contains(first.commandString, "'\\''") {
			t.Fatalf("command does not safely quote apostrophe: %q", first.commandString)
		}
		if !strings.HasPrefix(first.commandString, first.containmentGuard+" && ") {
			t.Fatalf("caller command does not execute its containment guard: %q", first.commandString)
		}
	})

	t.Run("no-escape guard is concrete and unsafe paths fail before caller execution", func(t *testing.T) {
		binding := mustBinding(t, structured, []any{openAIChatTool("write_file", structuredSchema())})
		for _, path := range []string{"../escape", "/etc/passwd", ".iop/job/r3/../../escape", "bad;rm"} {
			if _, err := encodeWorkspaceCall(binding, opKindWrite, normalizedToolCall{ID: "public-3", Name: "write_file", Arguments: map[string]any{"path": path, "content": "x"}}); err == nil {
				t.Fatalf("unsafe path %q was accepted", path)
			}
		}
		payload, err := encodeWorkspaceCall(binding, opKindWrite, normalizedToolCall{ID: "public-4", Name: "write_file", Arguments: map[string]any{"path": ".iop/job/r4/plan.md", "content": "x"}})
		if err != nil {
			t.Fatalf("encode safe path: %v", err)
		}
		for _, required := range []string{"IOP_WS_ROOT=", "IOP_WORKSPACE_CWD", `realpath "`, "IOP_WS_CANDIDATE=", "path escapes workspace root"} {
			if !strings.Contains(payload.containmentGuard, required) {
				t.Fatalf("guard missing %q: %s", required, payload.containmentGuard)
			}
		}
		if strings.Contains(payload.containmentGuard, "realpath -e") {
			t.Fatalf("guard contains GNU-only realpath option: %s", payload.containmentGuard)
		}
		if !strings.Contains(payload.containmentGuard, `IOP_WS_CANDIDATE="$IOP_WS_ROOT/.iop/job/r4/plan.md"`) {
			t.Fatalf("guard does not retain exact candidate path: %s", payload.containmentGuard)
		}
	})
}

func TestWorkspaceBindingCommandModeRequiresCollectedProjection(t *testing.T) {
	command := mustBinding(t, fullWorkspaceAlternative("command", "bash", true), []any{openAIChatTool("bash", commandSchema())})
	if !command.requiresCollectedProjection() {
		t.Fatal("command-mode binding must collect before caller projection")
	}
	structured := mustBinding(t, fullWorkspaceAlternative("structured", "workspace", false), []any{openAIChatTool("workspace", structuredSchema())})
	if structured.requiresCollectedProjection() {
		t.Fatal("structured binding unexpectedly disabled progressive projection")
	}
}

func TestWorkspaceBindingReceipts(t *testing.T) {
	binding := mustBinding(t, workspaceAlternative("structured", "write_file", false, true), []any{openAIChatTool("write_file", structuredSchema())})
	payload, err := encodeWorkspaceCall(binding, opKindWrite, normalizedToolCall{
		ID: "public-receipt", ProviderCallID: "provider-receipt", Name: "write_file",
		Arguments: map[string]any{"path": ".iop/job/r5/plan.md", "content": "plan"},
	})
	if err != nil {
		t.Fatalf("encode payload: %v", err)
	}

	t.Run("configured exact receipt accepts either issued identity", func(t *testing.T) {
		for _, id := range []string{"public-receipt", "provider-receipt"} {
			receipt := matchResultReceipt(binding, payload, workspaceResult{callID: id, status: "success", body: []byte(`{"written":true}`)})
			if !receipt.matched || receipt.fingerprint != binding.fingerprint || receipt.path != payload.safePath {
				t.Fatalf("valid receipt did not correlate: %#v", receipt)
			}
		}
	})

	for name, result := range map[string]workspaceResult{
		"opaque":         {callID: "public-receipt", status: "success"},
		"error":          {callID: "public-receipt", status: "error", body: []byte(`{"written":true}`)},
		"embedded error": {callID: "public-receipt", status: "success", body: []byte(`{"written":true,"error":{"message":"nope"}}`)},
		"trailing JSON":  {callID: "public-receipt", status: "success", body: []byte(`{"written":true} {"error":"nope"}`)},
		"wrong id":       {callID: "other", status: "success", body: []byte(`{"written":true}`)},
		"wrong body":     {callID: "public-receipt", status: "success", body: []byte(`{"written":false}`)},
		"arbitrary JSON": {callID: "public-receipt", status: "success", body: []byte(`{"anything":"else"}`)},
	} {
		t.Run(name, func(t *testing.T) {
			if receipt := matchResultReceipt(binding, payload, result); receipt.matched {
				t.Fatalf("mismatched receipt was accepted: %#v", receipt)
			}
		})
	}

	t.Run("rejects every issued payload mutation", func(t *testing.T) {
		mutations := map[string]func(*workspaceEncodedPayload){
			"operation": func(p *workspaceEncodedPayload) { p.operation = opKindPrepare },
			"path":      func(p *workspaceEncodedPayload) { p.safePath = ".iop/job/r5/review.md" },
			"arguments": func(p *workspaceEncodedPayload) { p.structuredArgs["content"] = "mutated" },
			"guard":     func(p *workspaceEncodedPayload) { p.containmentGuard = "mutated" },
		}
		for name, mutate := range mutations {
			t.Run(name, func(t *testing.T) {
				copy := cloneWorkspacePayload(payload)
				mutate(copy)
				if receipt := matchResultReceipt(binding, copy, workspaceResult{callID: "public-receipt", status: "success", body: []byte(`{"written":true}`)}); receipt.matched {
					t.Fatalf("mutated payload unexpectedly matched: %#v", receipt)
				}
			})
		}
	})
}

func TestWorkspaceResultExactness(t *testing.T) {
	tests := []struct {
		name      string
		result    workspaceResult
		wantExact bool
	}{
		{
			name:      "empty success body is opaque",
			result:    workspaceResult{status: "success", body: nil},
			wantExact: false,
		},
		{
			name:      "whitespace success body is opaque",
			result:    workspaceResult{status: "success", body: []byte("   \n\t ")},
			wantExact: false,
		},
		{
			name:      "empty explicit error is exact",
			result:    workspaceResult{status: "error", body: nil},
			wantExact: true,
		},
		{
			name:      "non-empty matcher failure is exact",
			result:    workspaceResult{status: "success", body: []byte(`{"written":false}`)},
			wantExact: true,
		},
		{
			name:      "malformed json body is opaque",
			result:    workspaceResult{status: "success", body: []byte(`not-json`)},
			wantExact: false,
		},
		{
			name:      "trailing json body is opaque",
			result:    workspaceResult{status: "success", body: []byte(`{"written":true} {"error":"nope"}`)},
			wantExact: false,
		},
		{
			name:      "valid success receipt body is exact",
			result:    workspaceResult{status: "success", body: []byte(`{"written":true}`)},
			wantExact: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := workspaceResultIsExact(tt.result); got != tt.wantExact {
				t.Fatalf("workspaceResultIsExact() = %v, want %v", got, tt.wantExact)
			}
		})
	}
}

func TestWorkspaceOperationMatrix(t *testing.T) {
	nativeSchema, err := json.Marshal(structuredSchema())
	if err != nil {
		t.Fatalf("marshal native schema: %v", err)
	}
	for _, tc := range []struct {
		name    string
		command bool
		tools   any
	}{
		{name: "structured", tools: []any{openAIChatTool("workspace", structuredSchema())}},
		{name: "command", command: true, tools: []any{openAIChatTool("workspace", commandSchema())}},
		{name: "native Anthropic", tools: []anthropicTool{{Name: "workspace", Description: "workspace tool", InputSchema: nativeSchema}}},
	} {
		t.Run(tc.name, func(t *testing.T) {
			binding := mustBinding(t, fullWorkspaceAlternative(tc.name, "workspace", tc.command), tc.tools)
			for _, operation := range canonicalOperationOrder {
				args := map[string]any{"path": ".iop/job/r6/" + string(operation) + ".md"}
				if operation == opKindWrite {
					args["content"] = "content"
				}
				payload, err := encodeWorkspaceCall(binding, operation, normalizedToolCall{ID: "call-" + string(operation), Name: "workspace", Arguments: args})
				if err != nil {
					t.Fatalf("encode %s: %v", operation, err)
				}
				if payload.operation != operation || payload.correlationDigest == "" {
					t.Fatalf("payload for %s is not sealed: %#v", operation, payload)
				}
				if receipt := matchResultReceipt(binding, payload, workspaceResult{callID: payload.publicCallID, status: "success", body: []byte(`{"written":true}`)}); !receipt.matched {
					t.Fatalf("valid %s receipt did not match: %#v", operation, receipt)
				}
			}
		})
	}

	t.Run("ordered complete alternatives and missing tools", func(t *testing.T) {
		first := fullWorkspaceAlternative("first", "first_workspace", false)
		second := fullWorkspaceAlternative("second", "second_workspace", false)
		tools := []any{openAIChatTool("second_workspace", structuredSchema()), openAIChatTool("first_workspace", structuredSchema())}
		binding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{second, first}, tools)
		if err != nil || binding.alternativeName != "second" {
			t.Fatalf("configured first complete alternative was not selected: binding=%#v err=%v", binding, err)
		}
		if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{first}, []any{openAIChatTool("first_workspace", structuredSchema()), unrelatedTool()}); err != nil {
			t.Fatalf("extra unrelated tool must not invalidate a complete alternative: %v", err)
		}
		if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{first}, []any{unrelatedTool()}); err == nil {
			t.Fatal("missing complete operation tool unexpectedly bound")
		}
	})
}

func mustBinding(t *testing.T, alternative config.ExecutionWorkspaceToolAlternative, tools any) *workspaceBinding {
	t.Helper()
	binding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{alternative}, tools)
	if err != nil {
		t.Fatalf("compile binding: %v", err)
	}
	return binding
}

func workspaceAlternative(name, toolName string, command, createsParents bool) config.ExecutionWorkspaceToolAlternative {
	argumentMap := map[string]any{"path": "path", "content": "content"}
	prepareArgumentMap := map[string]any{"path": "path"}
	if command {
		argumentMap = map[string]any{"path": "path", "content": "content", "command": "command", "argv": []any{"write", "{path}", "{content}"}}
		prepareArgumentMap = map[string]any{"path": "path", "command": "command", "argv": []any{"mkdir", "{path}"}}
	}
	return config.ExecutionWorkspaceToolAlternative{
		Name: name,
		Operations: map[string]config.ExecutionWorkspaceOperation{
			"prepare": {ToolName: toolName, SchemaMatcher: map[string]any{"type": "object"}, ArgumentMap: prepareArgumentMap, ResultMatcher: successMatcher(), CreatesParents: true},
			"write":   {ToolName: toolName, SchemaMatcher: map[string]any{"type": "object"}, ArgumentMap: argumentMap, ResultMatcher: successMatcher(), CreatesParents: createsParents},
		},
	}
}

func fullWorkspaceAlternative(name, toolName string, command bool) config.ExecutionWorkspaceToolAlternative {
	alternative := workspaceAlternative(name, toolName, command, true)
	for _, operation := range []workspaceOperationKind{opKindRead, opKindDelete} {
		argumentMap := map[string]any{"path": "path"}
		if command {
			argumentMap = map[string]any{"path": "path", "command": "command", "argv": []any{string(operation), "{path}"}}
		}
		alternative.Operations[string(operation)] = config.ExecutionWorkspaceOperation{
			ToolName: toolName, SchemaMatcher: map[string]any{"type": "object"}, ArgumentMap: argumentMap, ResultMatcher: successMatcher(), CreatesParents: true,
		}
	}
	return alternative
}

func cloneWorkspacePayload(payload *workspaceEncodedPayload) *workspaceEncodedPayload {
	copy := *payload
	copy.structuredArgs = cloneAnyMap(payload.structuredArgs)
	copy.commandArgv = append([]string(nil), payload.commandArgv...)
	return &copy
}

func successMatcher() map[string]any {
	return map[string]any{"status": "success", "result": map[string]any{"written": true}}
}

func structuredSchema() map[string]any {
	return map[string]any{"type": "object", "properties": map[string]any{"path": map[string]any{"type": "string"}, "content": map[string]any{}}, "required": []any{"path", "content"}}
}

func commandSchema() map[string]any {
	return map[string]any{"type": "object", "properties": map[string]any{"command": map[string]any{"type": "string"}}}
}

func openAIChatTool(name string, schema map[string]any) map[string]any {
	return map[string]any{"type": "function", "function": map[string]any{"name": name, "description": "workspace tool", "parameters": schema}}
}

func anthropicWorkspaceTool(name string, schema map[string]any) map[string]any {
	return map[string]any{"name": name, "description": "workspace tool", "input_schema": schema}
}

func unrelatedTool() map[string]any {
	return openAIChatTool("get_weather", map[string]any{"type": "object", "properties": map[string]any{"city": map[string]any{"type": "string"}}})
}
