package config_test

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

	"iop/packages/go/config"
)

func TestLoadEdge_ModelCatalogEmptyProviderIDRejected(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "qwen3.6:35b"
    providers:
      "": "model-a"
nodes:
  - id: "node-01"
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
`
	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 provider id in models[].providers")
	}
	if !strings.Contains(err.Error(), "provider id must not be empty") {
		t.Fatalf("expected error mentioning provider id must not be empty, got %v", err)
	}
}

func TestLoadEdge_ModelCatalogEmptyServedModelRejected(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
models:
  - id: "qwen3.6:35b"
    providers:
      vllm-gpu: ""
nodes:
  - id: "node-01"
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
`
	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 served model name")
	}
	if !strings.Contains(err.Error(), "served model name must not be empty") {
		t.Fatalf("expected error mentioning served model name must not be empty, got %v", err)
	}
}

func TestModelCatalogEntry_Validate(t *testing.T) {
	providerIDs := map[string]struct{}{
		"vllm-gpu":   {},
		"ollama-loc": {},
	}

	// Happy path with serveModels
	serveModels := map[string]map[string]struct{}{
		"vllm-gpu":   {"nvidia/Qwen3.6-35B": {}},
		"ollama-loc": {"qwen3.6:35b": {}},
	}
	e := config.ModelCatalogEntry{
		ID:                         "qwen3.6:35b",
		DisplayName:                "Qwen 3.6 35B",
		ContextWindowTokens:        262144,
		DefaultMaxTokens:           32768,
		MinMaxTokens:               32768,
		DefaultThinkingTokenBudget: 8192,
		Providers: map[string]string{
			"vllm-gpu":   "nvidia/Qwen3.6-35B",
			"ollama-loc": "qwen3.6:35b",
		},
	}
	if err := e.Validate(providerIDs, serveModels); err != nil {
		t.Fatalf("expected no error, got: %v", err)
	}

	// Happy path without serveModels (legacy behavior)
	e5 := config.ModelCatalogEntry{
		ID:        "test",
		Providers: map[string]string{"vllm-gpu": "m"},
	}
	if err := e5.Validate(providerIDs, nil); err != nil {
		t.Fatalf("expected no error with nil serveModels, got: %v", err)
	}

	// Trimmed empty ID
	e2 := config.ModelCatalogEntry{
		ID:        "  ",
		Providers: map[string]string{"vllm-gpu": "m"},
	}
	if err := e2.Validate(providerIDs, serveModels); err == nil {
		t.Fatal("expected error for trimmed empty ID")
	}

	// Empty providers map
	e3 := config.ModelCatalogEntry{
		ID:        "test",
		Providers: map[string]string{},
	}
	if err := e3.Validate(providerIDs, serveModels); err == nil {
		t.Fatal("expected error for empty providers map")
	}

	// Unresolved provider
	e4 := config.ModelCatalogEntry{
		ID: "test",
		Providers: map[string]string{
			"unknown-provider": "m",
		},
	}
	if err := e4.Validate(providerIDs, serveModels); err == nil {
		t.Fatal("expected error for unresolved provider")
	}

	// Negative and inconsistent generation policy
	for _, tc := range []struct {
		name  string
		entry config.ModelCatalogEntry
	}{
		{
			name: "negative context window tokens",
			entry: config.ModelCatalogEntry{
				ID:                  "test",
				ContextWindowTokens: -1,
				Providers:           map[string]string{"vllm-gpu": "m"},
			},
		},
		{
			name: "negative default max tokens",
			entry: config.ModelCatalogEntry{
				ID:               "test",
				DefaultMaxTokens: -1,
				Providers:        map[string]string{"vllm-gpu": "m"},
			},
		},
		{
			name: "negative min max tokens",
			entry: config.ModelCatalogEntry{
				ID:           "test",
				MinMaxTokens: -1,
				Providers:    map[string]string{"vllm-gpu": "m"},
			},
		},
		{
			name: "negative thinking budget",
			entry: config.ModelCatalogEntry{
				ID:                         "test",
				DefaultThinkingTokenBudget: -1,
				Providers:                  map[string]string{"vllm-gpu": "m"},
			},
		},
		{
			name: "default below min",
			entry: config.ModelCatalogEntry{
				ID:               "test",
				DefaultMaxTokens: 8,
				MinMaxTokens:     16,
				Providers:        map[string]string{"vllm-gpu": "m"},
			},
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			if err := tc.entry.Validate(providerIDs, nil); err == nil {
				t.Fatal("expected error for invalid generation policy")
			}
		})
	}
}

func TestNodeProviderConf_Validate(t *testing.T) {
	// Happy path
	p := config.NodeProviderConf{
		ID:       "p1",
		Type:     "vllm",
		Category: config.CategoryAPI,
		Models:   []string{"model-a", "model-b"},
		Capacity: 4,
	}
	if err := p.Validate(); err != nil {
		t.Fatalf("expected no error, got: %v", err)
	}

	// Empty ID
	p2 := config.NodeProviderConf{ID: "", Type: "vllm", Category: config.CategoryAPI}
	if err := p2.Validate(); err == nil {
		t.Fatal("expected error for empty ID")
	}

	// Empty Type
	p3 := config.NodeProviderConf{ID: "p1", Type: "", Category: config.CategoryAPI}
	if err := p3.Validate(); err == nil {
		t.Fatal("expected error for empty Type")
	}

	// Invalid Category
	p4 := config.NodeProviderConf{ID: "p1", Type: "vllm", Category: "invalid"}
	if err := p4.Validate(); err == nil {
		t.Fatal("expected error for invalid category")
	}

	// Empty model in models list
	p5 := config.NodeProviderConf{
		ID:       "p1",
		Type:     "vllm",
		Category: config.CategoryAPI,
		Models:   []string{"", "real"},
	}
	if err := p5.Validate(); err == nil {
		t.Fatal("expected error for empty model in list")
	}

	// Negative capacity
	p6 := config.NodeProviderConf{
		ID:       "p1",
		Type:     "vllm",
		Category: config.CategoryAPI,
		Capacity: -1,
	}
	if err := p6.Validate(); err == nil {
		t.Fatal("expected error for negative capacity")
	}

	// Negative max_queue
	p7 := config.NodeProviderConf{
		ID:       "p1",
		Type:     "vllm",
		Category: config.CategoryAPI,
		MaxQueue: -1,
	}
	if err := p7.Validate(); err == nil {
		t.Fatal("expected error for negative max_queue")
	}

	// Negative queue_timeout_ms
	p8 := config.NodeProviderConf{
		ID:             "p1",
		Type:           "vllm",
		Category:       config.CategoryAPI,
		QueueTimeoutMS: -1,
	}
	if err := p8.Validate(); err == nil {
		t.Fatal("expected error for negative queue_timeout_ms")
	}
}

func TestLoadEdge_ProviderPoolLegacyCompatibility(t *testing.T) {
	// Legacy openai.model_routes must still work alongside the new models[]/providers[].
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
openai:
  enabled: true
  provider_id: "test-provider"
  model_routes:
    - model: "qwen"
      adapter: "ollama"
      target: "qwen"
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"
`
	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.OpenAI.ModelRoutes) != 1 {
		t.Fatalf("expected 1 legacy route, got %d", len(cfg.OpenAI.ModelRoutes))
	}
	if len(cfg.Models) != 1 {
		t.Fatalf("expected 1 models[] entry, got %d", len(cfg.Models))
	}
}

func TestLoadEdge_ProviderFirstNodeProvidersHappyPath(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "gpu-node"
    providers:
      - id: "openai-provider"
        type: "openai_compat"
        category: "api"
        endpoint: "http://127.0.0.1:8000/v1"
        headers:
          Authorization: "Bearer test"
        capacity: 5
      - id: "ollama-provider"
        type: "ollama"
        category: "local_inference"
        base_url: "http://127.0.0.1:11434"
        context_size: 4096
        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.Nodes) != 1 {
		t.Fatalf("expected 1 node, got %d", len(cfg.Nodes))
	}
	providers := cfg.Nodes[0].Providers
	if len(providers) != 2 {
		t.Fatalf("expected 2 providers, got %d", len(providers))
	}

	// Verify openai-provider
	p1 := providers[0]
	if p1.ID != "openai-provider" || p1.Type != "openai_compat" || p1.Endpoint != "http://127.0.0.1:8000/v1" {
		t.Errorf("unexpected openai-provider fields: %+v", p1)
	}
	if p1.Headers["Authorization"] != "Bearer test" && p1.Headers["authorization"] != "Bearer test" {
		t.Errorf("expected Authorization header, got %v", p1.Headers)
	}

	// Verify ollama-provider
	p2 := providers[1]
	if p2.ID != "ollama-provider" || p2.Type != "ollama" || p2.BaseURL != "http://127.0.0.1:11434" || p2.ContextSize != 4096 {
		t.Errorf("unexpected ollama-provider fields: %+v", p2)
	}
}

func TestLoadEdge_RejectWhitespaceProviderType(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "local"
    providers:
      - id: "whitespace-provider"
        type: " "
        category: "api"
        endpoint: "http://127.0.0.1:8000/v1"
`
	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 whitespace provider type, got nil")
	}
	if !strings.Contains(err.Error(), "type must not be empty") {
		t.Fatalf("expected error containing 'type must not be empty', got %v", err)
	}
}

// REVIEW_REVIEW_COMPAT-1: TestLoadEdge_LegacyOnlyConfigRegression
// verifies that a pure legacy-only config (adapters only, no providers)
// still loads successfully and the node has an empty Providers list.
func TestLoadEdge_LegacyOnlyConfigRegression(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "local"
    adapters:
      ollama:
        enabled: true
        base_url: "http://127.0.0.1:11434"
`
	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("LoadEdge should succeed for pure legacy-only config: %v", err)
	}
	if len(cfg.Nodes) != 1 {
		t.Fatalf("expected 1 node, got %d", len(cfg.Nodes))
	}
	if len(cfg.Nodes[0].Providers) != 0 {
		t.Fatalf("expected empty Providers list for legacy-only config, got %d providers", len(cfg.Nodes[0].Providers))
	}
}

// COMPAT-1: TestLoadEdge_ProviderFirstLegacyIdenticalMixedAllowed verifies that
// provider-first resources and legacy adapters with matching fields coexist
// without errors when the key (provider id == adapter instance name) is shared.
func TestLoadEdge_ProviderFirstLegacyIdenticalMixedAllowed(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "local"
    adapters:
      ollama:
        enabled: true
        base_url: "http://127.0.0.1:11434"
        context_size: 4096
        capacity: 2
    providers:
      - id: "ollama"
        type: "ollama"
        category: "local_inference"
        base_url: "http://127.0.0.1:11434"
        models:
          - "llama3:8b"
        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("LoadEdge should succeed for identical mixed config: %v", err)
	}
	if len(cfg.Nodes) != 1 || len(cfg.Nodes[0].Providers) != 1 {
		t.Fatalf("expected 1 node with 1 provider, got %d nodes", len(cfg.Nodes))
	}
}

// COMPAT-1: TestLoadEdge_ProviderFirstLegacyConflictRejected verifies that
// provider-first resources and legacy adapters with different field values
// for the same key produce a validation error.
func TestLoadEdge_ProviderFirstLegacyConflictRejected(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "local"
    adapters:
      ollama:
        enabled: true
        base_url: "http://127.0.0.1:11434"
        capacity: 2
    providers:
      - id: "ollama"
        type: "ollama"
        category: "local_inference"
        base_url: "http://other-host:11434"
        models:
          - "llama3:8b"
        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 conflicting provider-first and legacy ollama config")
	}
	if !strings.Contains(err.Error(), "conflicts with adapters") {
		t.Fatalf("expected error containing 'conflicts with adapters', got %v", err)
	}
}

// Provider capacity is an admission limit and may be lower than the backing
// adapter's transport capacity.
func TestLoadEdge_ProviderCapacityMayBeLowerThanAdapter(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "local"
    adapters:
      ollama:
        enabled: true
        base_url: "http://127.0.0.1:11434"
        capacity: 2
    providers:
      - id: "ollama"
        type: "ollama"
        category: "local_inference"
        base_url: "http://127.0.0.1:11434"
        models:
          - "llama3:8b"
        capacity: 1
`
	if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
		t.Fatalf("write yaml: %v", err)
	}
	if _, err := config.LoadEdge(f); err != nil {
		t.Fatalf("lower provider admission capacity must load: %v", err)
	}
}

func TestLoadEdge_ProviderCapacityCannotExceedAdapter(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "local"
    adapters:
      ollama:
        enabled: true
        base_url: "http://127.0.0.1:11434"
        capacity: 3
    providers:
      - id: "ollama"
        type: "ollama"
        category: "local_inference"
        base_url: "http://127.0.0.1:11434"
        models:
          - "llama3:8b"
        capacity: 4
`
	if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
		t.Fatalf("write yaml: %v", err)
	}
	_, err := config.LoadEdge(f)
	if err == nil || !strings.Contains(err.Error(), "provider capacity exceeds adapter capacity") {
		t.Fatalf("provider capacity above adapter limit error = %v", err)
	}
}

func TestLoadEdge_OpenAICompatProviderCapacityMayBeLowerThanAdapter(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "local"
    adapters:
      openai_compat_instances:
        - name: "vllm-gpu"
          enabled: true
          endpoint: "http://127.0.0.1:8000/v1"
          capacity: 4
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
        endpoint: "http://127.0.0.1:8000/v1"
        models:
          - "model-a"
        capacity: 1
`
	if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
		t.Fatalf("write yaml: %v", err)
	}
	if _, err := config.LoadEdge(f); err != nil {
		t.Fatalf("lower provider admission capacity must load: %v", err)
	}
}

// TestLoadEdgeProviderLongContextCapacityValidation covers the provider-level
// long-context fields: a valid config loads the values, and the field-level
// invariants (non-negative, and total>0 when long_context_capacity>0) are enforced.
func TestLoadEdgeProviderLongContextCapacityValidation(t *testing.T) {
	validYAML := `
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"
    alias: "gpu-node"
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
        models:
          - "nvidia/Qwen3.6-35B"
        capacity: 4
        total_context_tokens: 524288
        long_context_capacity: 2
`
	t.Run("valid", func(t *testing.T) {
		dir := t.TempDir()
		f := filepath.Join(dir, "edge.yaml")
		if err := os.WriteFile(f, []byte(validYAML), 0o600); err != nil {
			t.Fatalf("write yaml: %v", err)
		}
		cfg, err := config.LoadEdge(f)
		if err != nil {
			t.Fatalf("load: %v", err)
		}
		prov := cfg.Nodes[0].Providers[0]
		if prov.TotalContextTokens != 524288 {
			t.Errorf("total_context_tokens = %d, want 524288", prov.TotalContextTokens)
		}
		if prov.LongContextCapacity != 2 {
			t.Errorf("long_context_capacity = %d, want 2", prov.LongContextCapacity)
		}
	})

	cases := []struct {
		name    string
		total   string
		long    string
		wantMsg string
	}{
		{"negative total", "total_context_tokens: -1", "long_context_capacity: 0", "total_context_tokens must be non-negative"},
		{"negative long", "total_context_tokens: 524288", "long_context_capacity: -1", "long_context_capacity must be non-negative"},
		{"long without total", "total_context_tokens: 0", "long_context_capacity: 2", "total_context_tokens must be positive when long_context_capacity"},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			dir := t.TempDir()
			f := filepath.Join(dir, "edge.yaml")
			yaml := fmt.Sprintf(`
server:
  listen: "0.0.0.0:9090"
nodes:
  - id: "node-gpu-01"
    alias: "gpu-node"
    providers:
      - id: "vllm-gpu"
        type: "vllm"
        category: "api"
        models:
          - "nvidia/Qwen3.6-35B"
        capacity: 4
        %s
        %s
`, tc.total, tc.long)
			if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
				t.Fatalf("write yaml: %v", err)
			}
			_, err := config.LoadEdge(f)
			if err == nil {
				t.Fatalf("expected error for %s", tc.name)
			}
			if !strings.Contains(err.Error(), tc.wantMsg) {
				t.Fatalf("expected error mentioning %q, got %v", tc.wantMsg, err)
			}
		})
	}
}

// TestLoadEdgeRejectsProviderLongContextBudgetBelowModelWindow verifies the
// cross-entry budget rule: a provider referenced by a model group must have
// total_context_tokens >= context_window_tokens * long_context_capacity.
func TestLoadEdgeRejectsProviderLongContextBudgetBelowModelWindow(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	// 262144 * 2 = 524288 required, but total is only 262144.
	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"
    alias: "gpu-node"
    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 total context budget")
	}
	if !strings.Contains(err.Error(), "total_context_tokens") || !strings.Contains(err.Error(), "long_context_capacity") {
		t.Fatalf("expected budget error mentioning total_context_tokens and long_context_capacity, got %v", err)
	}
}

func TestLoadEdge_MockConfigExplicitEnabled(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "test-node"
    token: "token-test"
    adapters:
      mock:
        enabled: true
`
	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 !cfg.Nodes[0].Adapters.Mock.Enabled {
		t.Fatal("expected mock.enabled=true")
	}
}

func TestLoadEdge_MockConfigOmittedDefaultsFalse(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "test-node"
    token: "token-test"
    adapters:
      ollama:
        enabled: true
        base_url: "http://127.0.0.1:11434"
`
	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 cfg.Nodes[0].Adapters.Mock.Enabled {
		t.Fatal("expected mock.enabled=false when omitted")
	}
}

func TestLoadEdge_MockConfigExplicitDisabled(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "test-node"
    token: "token-test"
    adapters:
      mock:
        enabled: false
`
	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 cfg.Nodes[0].Adapters.Mock.Enabled {
		t.Fatal("expected mock.enabled=false when explicitly disabled")
	}
}

func TestLoadEdge_NodeProviderGlobalUniqueness(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "node-a"
    providers:
      - id: "shared-provider"
        type: "ollama"
        category: "local_inference"
        models:
          - "model-a"
  - alias: "node-b"
    providers:
      - id: "shared-provider"
        type: "vllm"
        category: "api"
        models:
          - "model-b"
`
	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 duplicate provider id error across nodes")
	}
	if !strings.Contains(err.Error(), "shared-provider") {
		t.Fatalf("expected error to mention 'shared-provider', got %v", err)
	}
}

func TestLoadEdge_NodeProviderEnabledDefaultsTrue(t *testing.T) {
	dir := t.TempDir()
	f := filepath.Join(dir, "edge.yaml")
	yaml := `
server:
  listen: "0.0.0.0:9090"
nodes:
  - alias: "node-a"
    token: "tok-a"
    adapters:
      vllm:
        enabled: true
        endpoint: "http://127.0.0.1:8000/v1"
    providers:
      - id: "prov-default"
        type: "vllm"
        category: "api"
        adapter: "vllm"
        models: ["model-x"]
        capacity: 2
      - id: "prov-explicit-true"
        type: "vllm"
        category: "api"
        adapter: "vllm"
        models: ["model-y"]
        capacity: 2
        enabled: true
      - id: "prov-explicit-false"
        type: "vllm"
        category: "api"
        adapter: "vllm"
        models: ["model-z"]
        capacity: 2
        enabled: false
`
	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.Nodes) != 1 {
		t.Fatalf("expected 1 node, got %d", len(cfg.Nodes))
	}
	provs := cfg.Nodes[0].Providers
	if len(provs) != 3 {
		t.Fatalf("expected 3 providers, got %d", len(provs))
	}
	byID := map[string]config.NodeProviderConf{}
	for _, p := range provs {
		byID[p.ID] = p
	}

	// prov-default: Enabled is nil → ProviderEnabled returns true.
	def := byID["prov-default"]
	if def.Enabled != nil {
		t.Errorf("prov-default: expected Enabled=nil (omitted), got %v", def.Enabled)
	}
	if !config.ProviderEnabled(def) {
		t.Error("prov-default: ProviderEnabled must be true when Enabled is nil")
	}

	// prov-explicit-true: Enabled is *true → ProviderEnabled returns true.
	exTrue := byID["prov-explicit-true"]
	if exTrue.Enabled == nil || !*exTrue.Enabled {
		t.Errorf("prov-explicit-true: expected Enabled=*true, got %v", exTrue.Enabled)
	}
	if !config.ProviderEnabled(exTrue) {
		t.Error("prov-explicit-true: ProviderEnabled must be true when Enabled=true")
	}

	// prov-explicit-false: Enabled is *false → ProviderEnabled returns false.
	exFalse := byID["prov-explicit-false"]
	if exFalse.Enabled == nil || *exFalse.Enabled {
		t.Errorf("prov-explicit-false: expected Enabled=*false, got %v", exFalse.Enabled)
	}
	if config.ProviderEnabled(exFalse) {
		t.Error("prov-explicit-false: ProviderEnabled must be false when Enabled=false")
	}
}
