package config_test

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

	"iop/packages/go/config"
	"iop/packages/go/singlerequesttemplate"
)

// TestLoadEdgeModelExecutionPresetOneOf covers the one-of admission rule for
// ModelCatalogEntry: exactly one of providers or execution_preset must be set,
// preset ids must resolve to an execution_presets[] entry, and existing
// provider-only fixtures must keep working unchanged.
func TestLoadEdgeModelExecutionPresetOneOf(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")

	// ---- Happy path: provider-only (existing behavior) ----
	t.Run("provider-only entry loads unchanged", func(t *testing.T) {
		yaml := `
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
`
		if err := os.WriteFile(f, []byte(yaml), 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.Models) != 1 {
			t.Fatalf("expected 1 model, got %d", len(cfg.Models))
		}
		if cfg.Models[0].ExecutionPreset != "" {
			t.Errorf("provider-only entry should not have execution_preset set, got %q", cfg.Models[0].ExecutionPreset)
		}
		if len(cfg.Models[0].Providers) != 1 {
			t.Errorf("expected 1 provider, got %d", len(cfg.Models[0].Providers))
		}
	})

	// ---- Happy path: preset-only (virtual model) ----
	t.Run("preset-only entry loads as virtual model", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "virtual-model"
    execution_preset: "fast-path"
execution_presets:
  - id: "fast-path"
    selector:
      model: "virtual-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)
		}
		cfg, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
		if len(cfg.Models) != 1 {
			t.Fatalf("expected 1 model, got %d", len(cfg.Models))
		}
		m := cfg.Models[0]
		if m.ID != "virtual-model" {
			t.Errorf("model id = %q, want virtual-model", m.ID)
		}
		if m.ExecutionPreset != "fast-path" {
			t.Errorf("execution_preset = %q, want fast-path", m.ExecutionPreset)
		}
		if len(m.Providers) != 0 {
			t.Errorf("virtual model should have empty providers, got %v", m.Providers)
		}
	})

	// ---- Error: both providers and execution_preset set ----
	t.Run("both providers and execution_preset rejected", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "confused-model"
    execution_preset: "fast-path"
    providers:
      prov-a: "model-a"
execution_presets:
  - id: "fast-path"
    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 both providers and execution_preset set")
		}
		if !strings.Contains(err.Error(), "exactly one of providers or execution_preset must be set") {
			t.Fatalf("expected one-of error, got %v", err)
		}
	})

	// ---- Error: neither providers nor execution_preset ----
	t.Run("neither providers nor execution_preset rejected", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "empty-model"
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 neither providers nor execution_preset")
		}
		if !strings.Contains(err.Error(), "providers must not be empty") {
			t.Fatalf("expected providers must not be empty error, got %v", err)
		}
	})

	// ---- Error: dangling execution_preset id ----
	t.Run("dangling execution_preset id rejected", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "dangling-model"
    execution_preset: "non-existent-preset"
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 execution_preset id")
		}
		if !strings.Contains(err.Error(), "execution_preset") && !strings.Contains(err.Error(), "does not match any execution_presets") {
			t.Fatalf("expected dangling preset error, got %v", err)
		}
	})

	// ---- Compatibility: mixed catalog with both provider-only and preset-only ----
	t.Run("mixed catalog with provider-only and preset-only entries", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "qwen3.6:35b"
    providers:
      vllm-gpu: "nvidia/Qwen3.6-35B"
  - id: "virtual-light"
    execution_preset: "review-path"
execution_presets:
  - id: "review-path"
    selector:
      model: "qwen3.6:35b"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "local"
            model: "qwen3.6:35b"
          - role: "review"
            model: "qwen3.6:35b"
    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-gpu-01"
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
        models:
          - "nvidia/Qwen3.6-35B"
        capacity: 4
`
		if err := os.WriteFile(f, []byte(yaml), 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.Models) != 2 {
			t.Fatalf("expected 2 models, got %d", len(cfg.Models))
		}
		byID := map[string]config.ModelCatalogEntry{}
		for _, m := range cfg.Models {
			byID[m.ID] = m
		}
		// Provider-only entry should be unchanged.
		provModel := byID["qwen3.6:35b"]
		if len(provModel.Providers) != 1 {
			t.Errorf("provider-only model should have 1 provider, got %d", len(provModel.Providers))
		}
		if provModel.ExecutionPreset != "" {
			t.Errorf("provider-only model should not have execution_preset, got %q", provModel.ExecutionPreset)
		}
		// Virtual entry should reference the preset.
		virtualModel := byID["virtual-light"]
		if virtualModel.ExecutionPreset != "review-path" {
			t.Errorf("virtual model execution_preset = %q, want review-path", virtualModel.ExecutionPreset)
		}
		if len(virtualModel.Providers) != 0 {
			t.Errorf("virtual model should have empty providers, got %v", virtualModel.Providers)
		}
	})

	// ---- Compatibility: provider-only fixture with budget must still validate ----
	t.Run("provider-only entry with insufficient budget still rejected", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "qwen3.6:35b"
    context_window_tokens: 262144
    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
        total_context_tokens: 262144
        long_context_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 insufficient long-context budget on provider-only entry")
		}
		if !strings.Contains(err.Error(), "total_context_tokens") {
			t.Fatalf("expected budget error, got %v", err)
		}
	})

	// ---- Edge: whitespace-only execution_preset treated as unset ----
	t.Run("whitespace-only execution_preset treated as unset", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "whitespace-model"
    execution_preset: "   "
    providers:
      prov-a: "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)
		}
		cfg, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
		if len(cfg.Models) != 1 {
			t.Fatalf("expected 1 model, got %d", len(cfg.Models))
		}
		// Whitespace-only preset should be treated as unset, so provider-only
		// path should apply.
		if cfg.Models[0].ExecutionPreset != "" {
			t.Errorf("whitespace preset should be treated as unset, got %q", cfg.Models[0].ExecutionPreset)
		}
	})

	// ---- Normalization: non-empty execution_preset is stored canonically ----
	t.Run("non-empty execution_preset is normalized", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "qwen3.6:35b"
    providers:
      vllm-gpu: "nvidia/Qwen3.6-35B"
  - id: "virtual-fast"
    execution_preset: "  fast-path  "
execution_presets:
  - id: "fast-path"
    selector:
      model: "qwen3.6:35b"
    allowed_modes:
      - "direct"
    routes:
      direct:
        stages: []
nodes:
  - id: "node-gpu-01"
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
        models:
          - "nvidia/Qwen3.6-35B"
        capacity: 4
`
		if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		cfg, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
		byID := map[string]config.ModelCatalogEntry{}
		for _, m := range cfg.Models {
			byID[m.ID] = m
		}
		// The padded valid preset id must be persisted in canonical (trimmed)
		// form so exact downstream lookups match the admitted value.
		virtual := byID["virtual-fast"]
		if virtual.ExecutionPreset != "fast-path" {
			t.Errorf("execution_preset = %q, want canonical %q", virtual.ExecutionPreset, "fast-path")
		}
		if len(virtual.Providers) != 0 {
			t.Errorf("virtual model should have empty providers, got %v", virtual.Providers)
		}
		// Provider-only entry stays unchanged.
		prov := byID["qwen3.6:35b"]
		if prov.ExecutionPreset != "" {
			t.Errorf("provider-only entry should not have execution_preset set, got %q", prov.ExecutionPreset)
		}
		if len(prov.Providers) != 1 {
			t.Errorf("provider-only entry should have 1 provider, got %d", len(prov.Providers))
		}
	})

	// ---- Error: empty execution_preset string with no providers ----
	t.Run("explicit empty execution_preset with no providers rejected", func(t *testing.T) {
		yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "empty-preset-model"
    execution_preset: ""
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 execution_preset with no providers")
		}
		if !strings.Contains(err.Error(), "providers must not be empty") {
			t.Fatalf("expected providers must not be empty error, got %v", err)
		}
	})
}

// TestModelCatalogEntry_ValidateVirtualEntryUnit covers unit-level Validate
// behavior for the one-of rule without going through LoadEdge.
func TestModelCatalogEntry_ValidateVirtualEntryUnit(t *testing.T) {
	providerIDs := map[string]struct{}{
		"vllm-gpu": {},
	}
	serveModels := map[string]map[string]struct{}{
		"vllm-gpu": {"model-a": {}},
	}

	t.Run("provider-only validates", func(t *testing.T) {
		e := config.ModelCatalogEntry{
			ID:        "model-a",
			Providers: map[string]string{"vllm-gpu": "model-a"},
		}
		if err := e.Validate(providerIDs, serveModels); err != nil {
			t.Fatalf("expected no error, got: %v", err)
		}
	})

	t.Run("preset-only validates (returns nil, preset resolved later)", func(t *testing.T) {
		e := config.ModelCatalogEntry{
			ID:              "virtual-model",
			ExecutionPreset: "fast-path",
		}
		if err := e.Validate(providerIDs, serveModels); err != nil {
			t.Fatalf("expected no error for preset-only, got: %v", err)
		}
	})

	t.Run("both providers and execution_preset rejected", func(t *testing.T) {
		e := config.ModelCatalogEntry{
			ID:              "bad-model",
			Providers:       map[string]string{"vllm-gpu": "model-a"},
			ExecutionPreset: "fast-path",
		}
		if err := e.Validate(providerIDs, serveModels); err == nil {
			t.Fatal("expected error for both set")
		}
	})

	t.Run("neither providers nor execution_preset rejected", func(t *testing.T) {
		e := config.ModelCatalogEntry{
			ID: "empty-model",
		}
		if err := e.Validate(providerIDs, serveModels); err == nil {
			t.Fatal("expected error for neither set")
		}
	})

	t.Run("whitespace execution_preset treated as unset", func(t *testing.T) {
		e := config.ModelCatalogEntry{
			ID:              "ws-model",
			Providers:       map[string]string{"vllm-gpu": "model-a"},
			ExecutionPreset: "   ",
		}
		if err := e.Validate(providerIDs, serveModels); err != nil {
			t.Fatalf("expected no error (whitespace preset treated as unset), got: %v", err)
		}
	})
}

// customPlanTemplate and customReviewTemplate are valid operator-authored
// templates used to prove config-relative loading, per-file fallback, and
// filesystem-kind boundaries without depending on the built-in defaults.
const (
	customPlanTemplate   = "# Plan\n\n## Goal\n{{goal}}\n\n## Steps\n{{steps}}\n\n## Verification\n{{verification}}\n"
	customReviewTemplate = "# Review\n\n## Worker Item Status\n{{item_status}}\n\n## Worker Changes\n{{changes}}\n\n## Worker Verification\n{{verification}}\n\n## Deviations\n{{deviations}}\n"
)

func TestLoadEdgeSingleRequestTemplates(t *testing.T) {
	validPresetYAML := func(planFile, reviewFile string) string {
		tmplSection := ""
		if planFile != "" || reviewFile != "" {
			tmplSection = "      templates:\n"
			if planFile != "" {
				tmplSection += "        plan_file: " + planFile + "\n"
			}
			if reviewFile != "" {
				tmplSection += "        review_file: " + reviewFile + "\n"
			}
		}
		return `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "qwen3.6:35b"
    providers:
      vllm-gpu: "nvidia/Qwen3.6-35B"
  - id: "virtual-sr"
    execution_preset: "sr-preset"
execution_presets:
  - id: "sr-preset"
    selector:
      model: "qwen3.6:35b"
      options:
        reasoning_effort: "high"
    allowed_modes:
      - "light"
    routes:
      light:
        stages:
          - role: "plan"
            model: "qwen3.6:35b"
            options:
              reasoning_effort: "high"
          - role: "work"
            model: "qwen3.6:35b"
          - role: "review"
            model: "qwen3.6:35b"
            options:
              reasoning_effort: "high"
    single_request:
      workspace_ref: "ws-1"
      limits:
        wall_clock_ms: 60000
        timeout_ms: 30000
        max_tool_iterations: 10
        max_output_bytes: 1024
      stages:
        plan:
          model: "qwen3.6:35b"
          options:
            reasoning_effort: "high"
        work:
          model: "qwen3.6:35b"
        review:
          model: "qwen3.6:35b"
          options:
            reasoning_effort: "high"
` + tmplSection + `
nodes:
  - id: "node-gpu-01"
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
        models:
          - "nvidia/Qwen3.6-35B"
        capacity: 4
`
	}

	t.Run("built-in template fallback when templates omitted", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgSubdir := filepath.Join(rootDir, "sub", "config")
		if err := os.MkdirAll(cfgSubdir, 0o755); err != nil {
			t.Fatalf("mkdir: %v", err)
		}
		cfgPath := filepath.Join(cfgSubdir, "edge.yaml")
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		cfg, err := config.LoadEdge(cfgPath)
		if err != nil {
			t.Fatalf("LoadEdge failed: %v", err)
		}
		sr := cfg.ExecutionPresets[0].SingleRequest
		if sr.Templates.EffectivePlan == "" || sr.Templates.EffectiveReview == "" {
			t.Errorf("expected effective templates to be set to built-ins")
		}
		if sr.Templates.PlanFile != nil {
			t.Errorf("PlanFile = %q, want nil for an omitted field", *sr.Templates.PlanFile)
		}
		if sr.Templates.ReviewFile != nil {
			t.Errorf("ReviewFile = %q, want nil for an omitted field", *sr.Templates.ReviewFile)
		}
	})

	t.Run("relative path template resolution config-relative", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgSubdir := filepath.Join(rootDir, "sub", "config")
		tmplSubdir := filepath.Join(cfgSubdir, "tmpl")
		if err := os.MkdirAll(tmplSubdir, 0o755); err != nil {
			t.Fatalf("mkdir: %v", err)
		}
		cfgPath := filepath.Join(cfgSubdir, "edge.yaml")

		customPlan := "# Plan\n\n## Goal\n{{goal}}\n\n## Steps\n{{steps}}\n\n## Verification\n{{verification}}\n"
		customReview := customReviewTemplate

		if err := os.WriteFile(filepath.Join(tmplSubdir, "custom_plan.md"), []byte(customPlan), 0o600); err != nil {
			t.Fatalf("write custom plan: %v", err)
		}
		if err := os.WriteFile(filepath.Join(tmplSubdir, "custom_review.md"), []byte(customReview), 0o600); err != nil {
			t.Fatalf("write custom review: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("tmpl/custom_plan.md", "tmpl/custom_review.md")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		cfg, err := config.LoadEdge(cfgPath)
		if err != nil {
			t.Fatalf("LoadEdge failed: %v", err)
		}
		sr := cfg.ExecutionPresets[0].SingleRequest
		if sr.Templates.EffectivePlan != customPlan {
			t.Errorf("EffectivePlan = %q, want %q", sr.Templates.EffectivePlan, customPlan)
		}
		if sr.Templates.EffectiveReview != customReview {
			t.Errorf("EffectiveReview = %q, want %q", sr.Templates.EffectiveReview, customReview)
		}
		if sr.Templates.PlanFile == nil || *sr.Templates.PlanFile != "tmpl/custom_plan.md" {
			t.Errorf("PlanFile = %v, want the configured relative path", sr.Templates.PlanFile)
		}
		if sr.Templates.ReviewFile == nil || *sr.Templates.ReviewFile != "tmpl/custom_review.md" {
			t.Errorf("ReviewFile = %v, want the configured relative path", sr.Templates.ReviewFile)
		}
	})

	t.Run("missing configured template file fails closed", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("nonexistent_plan.md", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		_, err := config.LoadEdge(cfgPath)
		if err == nil {
			t.Fatalf("expected error for missing plan template file")
		}
	})

	t.Run("oversized template file 8193 bytes fails closed", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		oversizedPlan := "# Plan\n\n## Goal\n{{goal}}\n\n## Steps\n{{steps}}\n\n## Verification\n{{verification}}\n" + strings.Repeat(" ", 8193)
		if err := os.WriteFile(filepath.Join(rootDir, "oversized.md"), []byte(oversizedPlan), 0o600); err != nil {
			t.Fatalf("write oversized plan: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("oversized.md", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		_, err := config.LoadEdge(cfgPath)
		if err == nil {
			t.Fatalf("expected error for oversized template file")
		}
	})

	t.Run("invalid template content missing tokens fails closed", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		badPlan := "# Plan\n\n## Goal\nNo placeholders here\n"
		if err := os.WriteFile(filepath.Join(rootDir, "bad_plan.md"), []byte(badPlan), 0o600); err != nil {
			t.Fatalf("write bad plan: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("bad_plan.md", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		_, err := config.LoadEdge(cfgPath)
		if err == nil {
			t.Fatalf("expected error for invalid template content")
		}
	})

	// The config contract is relative-only: an absolute plan_file/review_file is
	// rejected before any filesystem access, so a readable, otherwise valid
	// template outside the edge.yaml directory must still fail closed.
	t.Run("absolute plan_file rejected before filesystem access", func(t *testing.T) {
		rootDir := t.TempDir()
		outsideDir := t.TempDir()
		absolutePlan := filepath.Join(outsideDir, "plan.md")
		if err := os.WriteFile(absolutePlan, []byte(customPlanTemplate), 0o600); err != nil {
			t.Fatalf("write absolute plan: %v", err)
		}
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML(absolutePlan, "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		_, err := config.LoadEdge(cfgPath)
		if err == nil {
			t.Fatalf("expected error for absolute plan_file %q", absolutePlan)
		}
		if !strings.Contains(err.Error(), "must be relative") {
			t.Fatalf("expected relative-path rejection, got: %v", err)
		}
	})

	t.Run("absolute review_file rejected before filesystem access", func(t *testing.T) {
		rootDir := t.TempDir()
		outsideDir := t.TempDir()
		absoluteReview := filepath.Join(outsideDir, "review.md")
		if err := os.WriteFile(absoluteReview, []byte(customReviewTemplate), 0o600); err != nil {
			t.Fatalf("write absolute review: %v", err)
		}
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("", absoluteReview)), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		_, err := config.LoadEdge(cfgPath)
		if err == nil {
			t.Fatalf("expected error for absolute review_file %q", absoluteReview)
		}
		if !strings.Contains(err.Error(), "must be relative") {
			t.Fatalf("expected relative-path rejection, got: %v", err)
		}
	})

	// plan_file and review_file fall back independently: configuring one file
	// must not replace the other with a loaded template or drop its default.
	t.Run("plan_file configured and review_file falls back", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		if err := os.WriteFile(filepath.Join(rootDir, "plan.md"), []byte(customPlanTemplate), 0o600); err != nil {
			t.Fatalf("write plan: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("plan.md", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		cfg, err := config.LoadEdge(cfgPath)
		if err != nil {
			t.Fatalf("LoadEdge failed: %v", err)
		}
		sr := cfg.ExecutionPresets[0].SingleRequest
		if sr.Templates.EffectivePlan != customPlanTemplate {
			t.Errorf("EffectivePlan = %q, want the configured custom template", sr.Templates.EffectivePlan)
		}
		if sr.Templates.EffectiveReview != singlerequesttemplate.DefaultReviewTemplate {
			t.Errorf("EffectiveReview = %q, want the built-in default", sr.Templates.EffectiveReview)
		}
		if sr.Templates.PlanFile == nil || *sr.Templates.PlanFile != "plan.md" {
			t.Errorf("PlanFile = %v, want the configured relative path", sr.Templates.PlanFile)
		}
		if sr.Templates.ReviewFile != nil {
			t.Errorf("ReviewFile = %q, want nil for an omitted field", *sr.Templates.ReviewFile)
		}
	})

	t.Run("review_file configured and plan_file falls back", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		if err := os.WriteFile(filepath.Join(rootDir, "review.md"), []byte(customReviewTemplate), 0o600); err != nil {
			t.Fatalf("write review: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("", "review.md")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		cfg, err := config.LoadEdge(cfgPath)
		if err != nil {
			t.Fatalf("LoadEdge failed: %v", err)
		}
		sr := cfg.ExecutionPresets[0].SingleRequest
		if sr.Templates.EffectiveReview != customReviewTemplate {
			t.Errorf("EffectiveReview = %q, want the configured custom template", sr.Templates.EffectiveReview)
		}
		if sr.Templates.EffectivePlan != singlerequesttemplate.DefaultPlanTemplate {
			t.Errorf("EffectivePlan = %q, want the built-in default", sr.Templates.EffectivePlan)
		}
		if sr.Templates.ReviewFile == nil || *sr.Templates.ReviewFile != "review.md" {
			t.Errorf("ReviewFile = %v, want the configured relative path", sr.Templates.ReviewFile)
		}
		if sr.Templates.PlanFile != nil {
			t.Errorf("PlanFile = %q, want nil for an omitted field", *sr.Templates.PlanFile)
		}
	})

	t.Run("exact 8192 byte template file accepted", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		exactPlan := customPlanTemplate + strings.Repeat(" ", singlerequesttemplate.MaxTemplateBytes-len(customPlanTemplate))
		if len(exactPlan) != singlerequesttemplate.MaxTemplateBytes {
			t.Fatalf("fixture size = %d, want %d", len(exactPlan), singlerequesttemplate.MaxTemplateBytes)
		}
		if err := os.WriteFile(filepath.Join(rootDir, "exact.md"), []byte(exactPlan), 0o600); err != nil {
			t.Fatalf("write exact plan: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("exact.md", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		cfg, err := config.LoadEdge(cfgPath)
		if err != nil {
			t.Fatalf("LoadEdge failed at the exact size boundary: %v", err)
		}
		if cfg.ExecutionPresets[0].SingleRequest.Templates.EffectivePlan != exactPlan {
			t.Errorf("EffectivePlan did not match the exact-size fixture")
		}
	})

	t.Run("symlinked template file fails closed", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		realPlan := filepath.Join(rootDir, "real_plan.md")
		if err := os.WriteFile(realPlan, []byte(customPlanTemplate), 0o600); err != nil {
			t.Fatalf("write real plan: %v", err)
		}
		if err := os.Symlink(realPlan, filepath.Join(rootDir, "link_plan.md")); err != nil {
			t.Skipf("symlink unsupported in this environment: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("link_plan.md", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		_, err := config.LoadEdge(cfgPath)
		if err == nil {
			t.Fatalf("expected error for symlinked template file")
		}
		if !strings.Contains(err.Error(), "regular file") {
			t.Fatalf("expected non-regular-file rejection, got: %v", err)
		}
	})

	t.Run("directory template path fails closed", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		if err := os.MkdirAll(filepath.Join(rootDir, "plan_dir"), 0o755); err != nil {
			t.Fatalf("mkdir: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("plan_dir", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		_, err := config.LoadEdge(cfgPath)
		if err == nil {
			t.Fatalf("expected error for directory template path")
		}
		if !strings.Contains(err.Error(), "regular file") {
			t.Fatalf("expected non-regular-file rejection, got: %v", err)
		}
	})

	t.Run("unreadable template file fails closed", func(t *testing.T) {
		if os.Geteuid() == 0 {
			t.Skip("running as root: mode bits do not deny read access")
		}
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		unreadable := filepath.Join(rootDir, "unreadable.md")
		if err := os.WriteFile(unreadable, []byte(customPlanTemplate), 0o600); err != nil {
			t.Fatalf("write unreadable plan: %v", err)
		}
		if err := os.Chmod(unreadable, 0o000); err != nil {
			t.Fatalf("chmod: %v", err)
		}
		t.Cleanup(func() { _ = os.Chmod(unreadable, 0o600) })
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("unreadable.md", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		if _, err := config.LoadEdge(cfgPath); err == nil {
			t.Fatalf("expected error for unreadable template file")
		}
	})

	t.Run("non-UTF-8 template file fails closed", func(t *testing.T) {
		rootDir := t.TempDir()
		cfgPath := filepath.Join(rootDir, "edge.yaml")
		invalid := append([]byte(customPlanTemplate), 0xff, 0xfe)
		if err := os.WriteFile(filepath.Join(rootDir, "invalid_utf8.md"), invalid, 0o600); err != nil {
			t.Fatalf("write invalid utf8 plan: %v", err)
		}
		if err := os.WriteFile(cfgPath, []byte(validPresetYAML("invalid_utf8.md", "")), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}

		_, err := config.LoadEdge(cfgPath)
		if err == nil {
			t.Fatalf("expected error for non-UTF-8 template file")
		}
		if !strings.Contains(err.Error(), "UTF-8") {
			t.Fatalf("expected UTF-8 rejection, got: %v", err)
		}
	})

	// Invalid grammar must fail closed for both files, not only plan_file.
	t.Run("invalid grammar matrix fails closed", func(t *testing.T) {
		cases := []struct {
			name       string
			planFile   string
			reviewFile string
			content    string
		}{
			{"plan missing heading", "bad.md", "", "## Goal\n{{goal}}\n\n## Steps\n{{steps}}\n\n## Verification\n{{verification}}\n"},
			{"plan decorated heading", "bad.md", "", "### Plan\n\n## Goal\n{{goal}}\n\n## Steps\n{{steps}}\n\n## Verification\n{{verification}}\n"},
			{"plan unknown placeholder", "bad.md", "", "# Plan\n\n## Goal\n{{goal}} {{owner}}\n\n## Steps\n{{steps}}\n\n## Verification\n{{verification}}\n"},
			{"plan delimiter residue", "bad.md", "", "# Plan\n\n## Goal\n{{goal}}}}\n\n## Steps\n{{steps}}\n\n## Verification\n{{verification}}\n"},
			{"plan duplicate placeholder", "bad.md", "", "# Plan\n\n## Goal\n{{goal}} {{goal}}\n\n## Steps\n{{steps}}\n\n## Verification\n{{verification}}\n"},
			{"review missing PASS", "", "bad.md", "# Review\n\n## Result\nFAIL\n\n## Checks\n{{checks}}\n\n## Verification\n{{verification}}\n\n## Summary\n{{summary}}\n"},
			{"review NOTPASS", "", "bad.md", "# Review\n\n## Result\nNOTPASS\n\n## Checks\n{{checks}}\n\n## Verification\n{{verification}}\n\n## Summary\n{{summary}}\n"},
			{"review decorated heading", "", "bad.md", "### Review\n\n## Result\nPASS\n\n## Checks\n{{checks}}\n\n## Verification\n{{verification}}\n\n## Summary\n{{summary}}\n"},
			{"review missing placeholder", "", "bad.md", "# Review\n\n## Result\nPASS\n\n## Checks\n{{checks}}\n\n## Verification\n{{verification}}\n\n## Summary\n"},
			{"review unknown placeholder", "", "bad.md", "# Review\n\n## Result\nPASS\n\n## Checks\n{{checks}} {{severity}}\n\n## Verification\n{{verification}}\n\n## Summary\n{{summary}}\n"},
			{"review wrong order", "", "bad.md", "# Review\n\n## Result\nPASS\n\n## Verification\n{{verification}}\n\n## Checks\n{{checks}}\n\n## Summary\n{{summary}}\n"},
		}

		for _, tc := range cases {
			t.Run(tc.name, func(t *testing.T) {
				rootDir := t.TempDir()
				cfgPath := filepath.Join(rootDir, "edge.yaml")
				if err := os.WriteFile(filepath.Join(rootDir, "bad.md"), []byte(tc.content), 0o600); err != nil {
					t.Fatalf("write template: %v", err)
				}
				if err := os.WriteFile(cfgPath, []byte(validPresetYAML(tc.planFile, tc.reviewFile)), 0o600); err != nil {
					t.Fatalf("write yaml: %v", err)
				}

				if _, err := config.LoadEdge(cfgPath); err == nil {
					t.Fatalf("expected error for %s", tc.name)
				}
			})
		}
	})

	// Only an omitted field selects the built-in default. An explicitly
	// configured empty, whitespace-only, or null path is a configuration error
	// and must be rejected with its own field context before the loader touches
	// the filesystem. Both YAML null spellings are covered because a present
	// null decodes into the same nil pointer as an absent key, so the rejection
	// has to happen on the raw preset structure before that presence is erased.
	t.Run("explicitly configured empty template path fails closed", func(t *testing.T) {
		cases := []struct {
			name       string
			planFile   string
			reviewFile string
			field      string
		}{
			{"empty plan_file", `""`, "", "single_request.templates.plan_file"},
			{"whitespace plan_file", `"   "`, "", "single_request.templates.plan_file"},
			{"null plan_file", "null", "", "single_request.templates.plan_file"},
			{"tilde plan_file", "~", "", "single_request.templates.plan_file"},
			{"empty review_file", "", `""`, "single_request.templates.review_file"},
			{"whitespace review_file", "", `"   "`, "single_request.templates.review_file"},
			{"null review_file", "", "null", "single_request.templates.review_file"},
			{"tilde review_file", "", "~", "single_request.templates.review_file"},
		}

		for _, tc := range cases {
			t.Run(tc.name, func(t *testing.T) {
				rootDir := t.TempDir()
				cfgPath := filepath.Join(rootDir, "edge.yaml")
				if err := os.WriteFile(cfgPath, []byte(validPresetYAML(tc.planFile, tc.reviewFile)), 0o600); err != nil {
					t.Fatalf("write yaml: %v", err)
				}

				_, err := config.LoadEdge(cfgPath)
				if err == nil {
					t.Fatalf("expected error for %s", tc.name)
				}
				if !strings.Contains(err.Error(), tc.field) {
					t.Errorf("expected %s context, got: %v", tc.field, err)
				}
				if !strings.Contains(err.Error(), "template path must not be empty") {
					t.Errorf("expected empty-path rejection, got: %v", err)
				}
				if strings.Contains(err.Error(), rootDir) {
					t.Errorf("rejection reached the filesystem: %v", err)
				}
			})
		}
	})
}

// TestExecutionSingleRequestTemplatePathPresenceClone proves the optional path
// cells survive Clone as independent values: mutating a clone must not reach
// the source policy, and the frozen effective templates must be unaffected.
func TestExecutionSingleRequestTemplatePathPresenceClone(t *testing.T) {
	planPath := "tmpl/plan.md"
	reviewPath := "tmpl/review.md"
	original := &config.ExecutionSingleRequestPolicy{
		WorkspaceRef: "ws-1",
		Templates: config.ExecutionSingleRequestTemplates{
			PlanFile:        &planPath,
			ReviewFile:      &reviewPath,
			EffectivePlan:   customPlanTemplate,
			EffectiveReview: customReviewTemplate,
		},
	}

	clone := original.Clone()
	if clone.Templates.PlanFile == nil || clone.Templates.ReviewFile == nil {
		t.Fatalf("clone dropped configured template paths: %+v", clone.Templates)
	}
	if clone.Templates.PlanFile == original.Templates.PlanFile {
		t.Errorf("clone aliases the plan_file pointer cell")
	}
	if clone.Templates.ReviewFile == original.Templates.ReviewFile {
		t.Errorf("clone aliases the review_file pointer cell")
	}

	*clone.Templates.PlanFile = "tmpl/other_plan.md"
	*clone.Templates.ReviewFile = "tmpl/other_review.md"
	clone.Templates.EffectivePlan = "mutated plan"

	if *original.Templates.PlanFile != planPath {
		t.Errorf("original PlanFile = %q, want %q", *original.Templates.PlanFile, planPath)
	}
	if *original.Templates.ReviewFile != reviewPath {
		t.Errorf("original ReviewFile = %q, want %q", *original.Templates.ReviewFile, reviewPath)
	}
	if original.Templates.EffectivePlan != customPlanTemplate {
		t.Errorf("original EffectivePlan changed: %q", original.Templates.EffectivePlan)
	}
	if original.Templates.EffectiveReview != customReviewTemplate {
		t.Errorf("original EffectiveReview changed: %q", original.Templates.EffectiveReview)
	}

	// A nil path must clone as omission, never as a configured empty value.
	omitted := &config.ExecutionSingleRequestPolicy{}
	omittedClone := omitted.Clone()
	if omittedClone.Templates.PlanFile != nil || omittedClone.Templates.ReviewFile != nil {
		t.Errorf("clone materialized omitted paths: %+v", omittedClone.Templates)
	}
}
