package config_test

import (
	"os"
	"path/filepath"
	"strings"
	"testing"

	"iop/packages/go/config"
)

// TestLoadEdgeExecutionPresetCatalog verifies that valid direct and light preset
// shapes decode, normalize, and survive LoadEdge alongside existing provider-
// only fixtures.
func TestLoadEdgeExecutionPresetCatalog(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")

	// Direct preset: no downstream stages, no options.
	directYAML := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "direct-default"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
	t.Run("direct preset loads", func(t *testing.T) {
		if err := os.WriteFile(f, []byte(directYAML), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		cfg, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
		if len(cfg.ExecutionPresets) != 1 {
			t.Fatalf("expected 1 preset, got %d", len(cfg.ExecutionPresets))
		}
		p := cfg.ExecutionPresets[0]
		if p.ID != "direct-default" {
			t.Errorf("preset id = %q, want %q", p.ID, "direct-default")
		}
		if p.Selector.Model != "model-a" {
			t.Errorf("selector model = %q, want %q", p.Selector.Model, "model-a")
		}
		if len(p.AllowedModes) != 1 || p.AllowedModes[0] != "direct" {
			t.Errorf("allowed_modes = %v, want [direct]", p.AllowedModes)
		}
		if len(p.Routes["direct"].Stages) != 0 {
			t.Errorf("expected 0 route stages for direct, got %d", len(p.Routes["direct"].Stages))
		}
	})

	// Route key with surrounding whitespace normalizes.
	whitespaceRouteYAML := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "whitespace-route"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      " direct ":
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
	t.Run("route key with surrounding whitespace normalizes", func(t *testing.T) {
		if err := os.WriteFile(f, []byte(whitespaceRouteYAML), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		cfg, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
		if len(cfg.ExecutionPresets) != 1 {
			t.Fatalf("expected 1 preset, got %d", len(cfg.ExecutionPresets))
		}
		p := cfg.ExecutionPresets[0]
		if _, ok := p.Routes["direct"]; !ok {
			t.Errorf("expected route key 'direct' after normalization, got routes %v", p.Routes)
		}
		if _, rawExists := p.Routes[" direct "]; rawExists {
			t.Errorf("raw un-trimmed route key ' direct ' should not remain in routes")
		}
	})

	// Hybrid multi-mode preset (direct and light).
	hybridYAML := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "hybrid-preset"
    selector:
      model: "model-a"
      options:
        temperature: 0.2
    allowed_modes:
      - "direct"
      - "light"
    routes:
      direct:
        stages: []
      light:
        stages:
          - role: "local"
            model: "model-a"
            options:
              timeout_ms: "30000"
          - role: "review"
            model: "model-b"
            options:
              max_retries: "2"
    workspace_tools:
      - name: "standard-fs"
        operations:
          " prepare ":
            tool_name: "mkdir_p"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          read:
            tool_name: "read_file"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "write_file"
            creates_parents: false
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "delete_file"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
	t.Run("hybrid multi-mode preset loads with workspace tools", func(t *testing.T) {
		if err := os.WriteFile(f, []byte(hybridYAML), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		cfg, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
		if len(cfg.ExecutionPresets) != 1 {
			t.Fatalf("expected 1 preset, got %d", len(cfg.ExecutionPresets))
		}
		p := cfg.ExecutionPresets[0]
		if p.ID != "hybrid-preset" {
			t.Errorf("preset id = %q, want %q", p.ID, "hybrid-preset")
		}
		if len(p.AllowedModes) != 2 || p.AllowedModes[0] != "direct" || p.AllowedModes[1] != "light" {
			t.Errorf("allowed_modes = %v, want [direct, light]", p.AllowedModes)
		}
		if len(p.Routes["light"].Stages) != 2 {
			t.Fatalf("expected 2 route stages for light, got %d", len(p.Routes["light"].Stages))
		}
		if p.Routes["light"].Stages[0].Role != "local" || p.Routes["light"].Stages[0].Model != "model-a" {
			t.Errorf("light stage 0 = %+v", p.Routes["light"].Stages[0])
		}
		if p.Routes["light"].Stages[1].Role != "review" || p.Routes["light"].Stages[1].Model != "model-b" {
			t.Errorf("light stage 1 = %+v", p.Routes["light"].Stages[1])
		}
		if len(p.WorkspaceTools) != 1 {
			t.Fatalf("expected 1 workspace tool alternative, got %d", len(p.WorkspaceTools))
		}
		wt := p.WorkspaceTools[0]
		if wt.Name != "standard-fs" {
			t.Errorf("workspace tool name = %q, want standard-fs", wt.Name)
		}
		if wt.Operations["write"].ToolName != "write_file" {
			t.Errorf("write operation tool_name = %q, want write_file", wt.Operations["write"].ToolName)
		}
		prepOp, hasPrep := wt.Operations["prepare"]
		if !hasPrep || prepOp.ToolName != "mkdir_p" {
			t.Errorf("prepare operation failed normalized key lookup, got %+v", prepOp)
		}
		if prepOp.SchemaMatcher == nil || prepOp.ArgumentMap == nil || prepOp.ResultMatcher == nil {
			t.Errorf("prepare operation missing matchers/mappings, got %+v", prepOp)
		}
	})

	// Multiple presets with mixed modes.
	multiYAML := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "fast-path"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
  - id: "review-path"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-b"
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "tee"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "rm"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
	t.Run("multiple presets with mixed modes", func(t *testing.T) {
		if err := os.WriteFile(f, []byte(multiYAML), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		cfg, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
		if len(cfg.ExecutionPresets) != 2 {
			t.Fatalf("expected 2 presets, got %d", len(cfg.ExecutionPresets))
		}
		byID := map[string]config.ExecutionPreset{}
		for _, p := range cfg.ExecutionPresets {
			byID[p.ID] = p
		}
		if _, ok := byID["fast-path"]; !ok {
			t.Fatal("expected fast-path preset")
		}
		if _, ok := byID["review-path"]; !ok {
			t.Fatal("expected review-path preset")
		}
	})

	// Empty execution_presets should load fine.
	emptyYAML := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
	t.Run("no presets defined loads fine", func(t *testing.T) {
		if err := os.WriteFile(f, []byte(emptyYAML), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
	})

	// Existing provider-only fixtures must remain compatible.
	providerOnlyYAML := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "qwen3.6:35b"
    providers:
      vllm-gpu: "nvidia/Qwen3.6-35B"
nodes:
  - id: "node-gpu-01"
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
        models:
          - "nvidia/Qwen3.6-35B"
        capacity: 4
`
	t.Run("provider-only config remains compatible", func(t *testing.T) {
		if err := os.WriteFile(f, []byte(providerOnlyYAML), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
	})
}

// TestLoadEdgeExecutionPresetRejectsInvalidShape verifies that invalid ids,
// routes, options, binding shapes, dangling references, and unsupported handlers fail closed.
func TestLoadEdgeExecutionPresetRejectsInvalidShape(t *testing.T) {
	t.Run("approved top-level list required map shape rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
execution_presets:
  presets:
    - id: "bad-shape"
      selector:
        model: "model-a"
      allowed_modes:
        - "direct"
      routes:
        direct:
          stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for map shape execution_presets")
		}
	})

	t.Run("unknown preset field rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "unknown-field-preset"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
    unsupported_spelling: "bad"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for unknown preset field")
		}
		if !strings.Contains(err.Error(), "unsupported_spelling") && !strings.Contains(err.Error(), "unused") {
			t.Fatalf("expected error mentioning unused/unknown field, got %v", err)
		}
	})

	t.Run("empty preset id rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: ""
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for empty preset id")
		}
		if !strings.Contains(err.Error(), "id must not be empty") {
			t.Fatalf("expected error mentioning id must not be empty, got %v", err)
		}
	})

	t.Run("duplicate preset id rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "dup"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
  - id: "dup"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for duplicate preset id")
		}
		if !strings.Contains(err.Error(), "duplicate preset id") {
			t.Fatalf("expected error mentioning duplicate preset id, got %v", err)
		}
	})

	t.Run("dangling selector model rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "dangling-selector"
    selector:
      model: "non-existent-model"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for dangling selector model")
		}
		if !strings.Contains(err.Error(), "not found in models catalog") {
			t.Fatalf("expected error mentioning not found in models catalog, got %v", err)
		}
	})

	t.Run("empty allowed_modes rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "no-modes"
    selector:
      model: "model-a"
    allowed_modes: []
    routes: {}
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for empty allowed_modes")
		}
		if !strings.Contains(err.Error(), "allowed_modes must not be empty") {
			t.Fatalf("expected error mentioning allowed_modes must not be empty, got %v", err)
		}
	})

	t.Run("unsupported mode heavy rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "heavy-path"
    selector:
      model: "model-a"
    allowed_modes:
      - "heavy"
    routes:
      heavy:
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for unsupported mode 'heavy'")
		}
		if !strings.Contains(err.Error(), "not a registered mode descriptor") {
			t.Fatalf("expected error mentioning not a registered mode descriptor, got %v", err)
		}
	})

	t.Run("missing route key for allowed mode rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "missing-route"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
      - "light"
    routes:
      direct:
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for missing route key for light mode")
		}
		if !strings.Contains(err.Error(), "missing route for allowed mode") {
			t.Fatalf("expected error mentioning missing route for allowed mode, got %v", err)
		}
	})

	t.Run("extra route key not in allowed_modes rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "extra-route"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-a"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for extra route key")
		}
		if !strings.Contains(err.Error(), "is not in allowed_modes") {
			t.Fatalf("expected error mentioning is not in allowed_modes, got %v", err)
		}
	})

	t.Run("duplicate route key after normalization rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "dup-route-key"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
      " direct ":
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for duplicate normalized route key")
		}
		if !strings.Contains(err.Error(), "duplicate route key") {
			t.Fatalf("expected error mentioning duplicate route key, got %v", err)
		}
	})

	t.Run("direct mode with downstream stages rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "direct-with-stages"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages:
          - role: "local"
            model: "model-a"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for direct mode with downstream stages")
		}
		if !strings.Contains(err.Error(), "declares no downstream stages") {
			t.Fatalf("expected error mentioning declares no downstream stages, got %v", err)
		}
	})

	t.Run("required stage option overflow rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "option-overflow"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
            options:
              opt1: "v1"
              opt2: "v2"
              opt3: "v3"
              opt4: "v4"
              opt5: "v5"
          - role: "review"
            model: "model-b"
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "tee"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "rm"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for stage option overflow on required stage")
		}
		if !strings.Contains(err.Error(), "allows at most 4 options") {
			t.Fatalf("expected error mentioning allows at most 4 options, got %v", err)
		}
	})

	t.Run("dangling stage model rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "dangling-stage-model"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "non-existent-review-model"
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "tee"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "rm"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for dangling stage model")
		}
		if !strings.Contains(err.Error(), "not found in models catalog") {
			t.Fatalf("expected error mentioning not found in models catalog, got %v", err)
		}
	})

	t.Run("missing prepare when write does not create parents rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "missing-prepare"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-b"
    workspace_tools:
      - name: "no-prepare-ws"
        operations:
          read:
            tool_name: "read_file"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "write_file"
            creates_parents: false
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "delete_file"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for missing prepare when write creates_parents=false")
		}
		if !strings.Contains(err.Error(), "prepare") && !strings.Contains(err.Error(), "does not create parents") {
			t.Fatalf("expected error mentioning prepare/creates_parents, got %v", err)
		}
	})

	t.Run("duplicate allowed mode rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "dup-mode"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
      - "direct"
    routes:
      direct:
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for duplicate allowed mode")
		}
		if !strings.Contains(err.Error(), "duplicate allowed mode") {
			t.Fatalf("expected error mentioning duplicate allowed mode, got %v", err)
		}
	})

	t.Run("duplicate workspace alternative name rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "dup-alt"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-b"
    workspace_tools:
      - name: "ws-dup"
        operations:
          read:
            tool_name: "cat"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "tee"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "rm"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
      - name: "ws-dup"
        operations:
          read:
            tool_name: "cat"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "tee"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "rm"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for duplicate workspace alternative name")
		}
		if !strings.Contains(err.Error(), "duplicate workspace_tools alternative name") {
			t.Fatalf("expected error mentioning duplicate workspace_tools alternative name, got %v", err)
		}
	})

	t.Run("light wrong stage order rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "wrong-order"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "review"
            model: "model-b"
          - role: "local"
            model: "model-a"
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "tee"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "rm"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for light wrong stage order")
		}
		if !strings.Contains(err.Error(), "stage[0] role is") || !strings.Contains(err.Error(), "want") {
			t.Fatalf("expected error mentioning stage role mismatch, got %v", err)
		}
	})

	t.Run("light wrong stage count rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "wrong-count"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "tee"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "rm"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for light wrong stage count")
		}
		if !strings.Contains(err.Error(), "requires stages") || !strings.Contains(err.Error(), "got 1 stages") {
			t.Fatalf("expected error mentioning required stages count, got %v", err)
		}
	})

	t.Run("light missing read operation rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "missing-read"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-b"
    workspace_tools:
      - name: "no-read-ws"
        operations:
          write:
            tool_name: "write_file"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "delete_file"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for missing read operation")
		}
		if !strings.Contains(err.Error(), "requires operation \"read\"") {
			t.Fatalf("expected error mentioning missing read operation, got %v", err)
		}
	})

	t.Run("light missing write operation rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "missing-write"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-b"
    workspace_tools:
      - name: "no-write-ws"
        operations:
          read:
            tool_name: "read_file"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          delete:
            tool_name: "delete_file"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for missing write operation")
		}
		if !strings.Contains(err.Error(), "requires operation \"write\"") {
			t.Fatalf("expected error mentioning missing write operation, got %v", err)
		}
	})

	t.Run("light missing delete operation rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "missing-delete"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-b"
    workspace_tools:
      - name: "no-delete-ws"
        operations:
          read:
            tool_name: "read_file"
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
          write:
            tool_name: "write_file"
            creates_parents: true
            schema_matcher:
              type: "object"
            argument_map:
              path: "path"
            result_matcher:
              status: "ok"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for missing delete operation")
		}
		if !strings.Contains(err.Error(), "requires operation \"delete\"") {
			t.Fatalf("expected error mentioning missing delete operation, got %v", err)
		}
	})

	t.Run("custom unregistered mode rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "custom-mode"
    selector:
      model: "model-a"
    allowed_modes:
      - "fast"
    routes:
      fast:
        stages: []
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for custom unregistered mode")
		}
		if !strings.Contains(err.Error(), "not a registered mode descriptor") {
			t.Fatalf("expected error mentioning not a registered mode descriptor, got %v", err)
		}
	})

	t.Run("empty model catalog with selector reference rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
execution_presets:
  - id: "empty-catalog-selector"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for selector model reference when models catalog is empty")
		}
		if !strings.Contains(err.Error(), "not found in models catalog") {
			t.Fatalf("expected error mentioning not found in models catalog, got %v", err)
		}
	})

	t.Run("empty model catalog with stage reference rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "empty-catalog-stage"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-b"
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher: { type: "object" }
            argument_map: { path: "path" }
            result_matcher: { status: "ok" }
          write:
            tool_name: "tee"
            creates_parents: true
            schema_matcher: { type: "object" }
            argument_map: { path: "path" }
            result_matcher: { status: "ok" }
          delete:
            tool_name: "rm"
            schema_matcher: { type: "object" }
            argument_map: { path: "path" }
            result_matcher: { status: "ok" }
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for stage model reference not in catalog")
		}
		if !strings.Contains(err.Error(), "not found in models catalog") {
			t.Fatalf("expected error mentioning not found in models catalog, got %v", err)
		}
	})

	t.Run("light mode with zero workspace_tools alternatives rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
  - id: "model-b"
    providers:
      prov-a: "model-b"
execution_presets:
  - id: "no-workspace-tools"
    selector:
      model: "model-a"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "model-a"
          - role: "review"
            model: "model-b"
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a", "model-b"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for light mode with no workspace_tools alternatives")
		}
		if !strings.Contains(err.Error(), "requires at least one workspace_tools alternative") {
			t.Fatalf("expected error mentioning requires at least one workspace_tools alternative, got %v", err)
		}
	})

	t.Run("workspace operation missing schema_matcher rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "missing-schema-matcher"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            argument_map: { path: "path" }
            result_matcher: { status: "ok" }
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for missing schema_matcher")
		}
		if !strings.Contains(err.Error(), "schema_matcher must not be empty") {
			t.Fatalf("expected error mentioning schema_matcher must not be empty, got %v", err)
		}
	})

	t.Run("workspace operation missing argument_map rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "missing-argument-map"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher: { type: "object" }
            result_matcher: { status: "ok" }
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for missing argument_map")
		}
		if !strings.Contains(err.Error(), "argument_map must not be empty") {
			t.Fatalf("expected error mentioning argument_map must not be empty, got %v", err)
		}
	})

	t.Run("workspace operation missing result_matcher rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "missing-result-matcher"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher: { type: "object" }
            argument_map: { path: "path" }
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for missing result_matcher")
		}
		if !strings.Contains(err.Error(), "result_matcher must not be empty") {
			t.Fatalf("expected error mentioning result_matcher must not be empty, got %v", err)
		}
	})

	t.Run("workspace operation duplicate key after normalization rejected", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "model-a"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "dup-op-key"
    selector:
      model: "model-a"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
    workspace_tools:
      - name: "ws1"
        operations:
          read:
            tool_name: "cat"
            schema_matcher: { type: "object" }
            argument_map: { path: "path" }
            result_matcher: { status: "ok" }
          " read ":
            tool_name: "cat2"
            schema_matcher: { type: "object" }
            argument_map: { path: "path" }
            result_matcher: { status: "ok" }
nodes:
  - id: "node-01"
    providers:
      - id: "prov-a"
        type: "ollama"
        category: "local_inference"
        models: ["model-a"]
        capacity: 2
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		_, err := config.LoadEdge(f)
		if err == nil {
			t.Fatal("expected error for duplicate operation key after normalization")
		}
		if !strings.Contains(err.Error(), "duplicate operation \"read\"") {
			t.Fatalf("expected error mentioning duplicate operation read, got %v", err)
		}
	})
}
