package config

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

// The heads graph is a fine-tuned copy of the embedder, and pointing both keys
// at one file degrades recall with no error and no log line (V-692). These are
// the shapes that used to boot clean.
func TestHeadsPathMustNotBeTheModelFile(t *testing.T) {
	dir := t.TempDir()
	model := filepath.Join(dir, "model.onnx")
	heads := filepath.Join(dir, "heads.onnx")
	for _, p := range []string{model, heads} {
		if err := os.WriteFile(p, []byte("onnx"), 0o600); err != nil {
			t.Fatalf("write %s: %v", p, err)
		}
	}
	link := filepath.Join(dir, "link.onnx")
	if err := os.Symlink(model, link); err != nil {
		t.Fatalf("symlink: %v", err)
	}

	// A path that stats and one that does not, because the guard compares the
	// cleaned string before it stats anything.
	for name, headsPath := range map[string]string{
		"the same path":     model,
		"a symlink to it":   link,
		"an uncleaned path": filepath.Join(dir, ".", "sub", "..", "model.onnx"),
		"a path on no disk": filepath.Join(dir, "absent.onnx"),
	} {
		t.Run(name, func(t *testing.T) {
			same := headsPath != filepath.Join(dir, "absent.onnx")
			err := voiceConfigWith(t, model, headsPath)
			if same && err == nil {
				t.Fatal("want a startup error, got a daemon that routes worse in silence")
			}
			if same && !strings.Contains(err.Error(), "heads_path") {
				t.Fatalf("the error does not name the key: %v", err)
			}
			if !same && err != nil {
				t.Fatalf("a distinct heads_path was refused: %v", err)
			}
		})
	}

	if err := voiceConfigWith(t, model, heads); err != nil {
		t.Fatalf("two distinct files were refused: %v", err)
	}
	if err := voiceConfigWith(t, model, ""); err != nil {
		t.Fatalf("no heads at all was refused: %v", err)
	}
}

// voiceConfigWith loads a minimal enabled voice block through the real Load, so
// the test exercises the startup path and not just the check in isolation.
func voiceConfigWith(t *testing.T, model, heads string) error {
	t.Helper()
	body := `{"voice":{"enabled":true,"bind":"127.0.0.1:9100","embedder":{` +
		`"model_path":"` + model + `","tokenizer_path":"/t.json","lib_path":"/l.so"`
	if heads != "" {
		body += `,"heads_path":"` + heads + `"`
	}
	body += `}}}`
	_, err := Load(writeConfig(t, body))
	return err
}

func TestVoiceRecallGateDefaults(t *testing.T) {
	cfg, err := Load(writeConfig(t, `{"voice":{"enabled":true,"bind":"127.0.0.1:9100"}}`))
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if got := cfg.Voice.QueryMinScore; got != DefaultQueryMinScore {
		t.Errorf("query score default = %.3f, want %.3f", got, DefaultQueryMinScore)
	}
	if got := cfg.Voice.QueryMinMargin; got != DefaultQueryMinMargin {
		t.Errorf("query margin default = %.3f, want %.3f", got, DefaultQueryMinMargin)
	}
}
