package config

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

func writeFile(t *testing.T, path, content string) {
	t.Helper()
	if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
		t.Fatal(err)
	}
}

func TestLoadMissingFiles(t *testing.T) {
	dir := t.TempDir()
	cfg, err := Load(filepath.Join(dir, "etc.yaml"), filepath.Join(dir, "user.yaml"))
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if *cfg != (Config{}) {
		t.Errorf("got %+v, want empty config", cfg)
	}
}

func TestLoadUserOverridesSystem(t *testing.T) {
	dir := t.TempDir()
	system := filepath.Join(dir, "etc.yaml")
	user := filepath.Join(dir, "user.yaml")
	writeFile(t, system, "runtime: docker\ndefault_mode: container\npersistence_dir: /srv/nest\n")
	writeFile(t, user, "runtime: podman\n")

	cfg, err := Load(system, user)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if cfg.Runtime != "podman" {
		t.Errorf("Runtime = %q, want podman (user wins)", cfg.Runtime)
	}
	if cfg.DefaultMode != "container" {
		t.Errorf("DefaultMode = %q, want container (inherited from system)", cfg.DefaultMode)
	}
	if cfg.PersistenceDir != "/srv/nest" {
		t.Errorf("PersistenceDir = %q, want /srv/nest", cfg.PersistenceDir)
	}
}

func TestLoadMalformed(t *testing.T) {
	dir := t.TempDir()
	system := filepath.Join(dir, "etc.yaml")
	writeFile(t, system, "runtime: [")

	_, err := Load(system, filepath.Join(dir, "user.yaml"))
	if err == nil || !strings.Contains(err.Error(), system) {
		t.Fatalf("err = %v, want error naming %s", err, system)
	}
}

func TestLoadInvalidValues(t *testing.T) {
	dir := t.TempDir()
	user := filepath.Join(dir, "user.yaml")
	writeFile(t, user, "runtime: containerd\n")

	_, err := Load(filepath.Join(dir, "etc.yaml"), user)
	if err == nil || !strings.Contains(err.Error(), "runtime must be") {
		t.Fatalf("err = %v, want runtime validation error", err)
	}
}

func TestResolveRuntime(t *testing.T) {
	cfg := &Config{Runtime: "docker"}
	if got := cfg.ResolveRuntime("podman"); got != "podman" {
		t.Errorf("flag: got %q, want podman", got)
	}
	if got := cfg.ResolveRuntime(""); got != "docker" {
		t.Errorf("config: got %q, want docker", got)
	}
	if got := (&Config{}).ResolveRuntime(""); got != "auto" {
		t.Errorf("default: got %q, want auto", got)
	}
}

func TestResolveMode(t *testing.T) {
	if _, err := (&Config{}).ResolveMode(true, true); err == nil {
		t.Error("conflicting flags: want usage error")
	}
	cfg := &Config{DefaultMode: "container"}
	cases := []struct {
		local, container bool
		cfg              *Config
		want             string
	}{
		{true, false, cfg, "local"},
		{false, true, cfg, "container"},
		{false, false, cfg, "container"},
		{false, false, &Config{}, "local"},
	}
	for _, tc := range cases {
		got, err := tc.cfg.ResolveMode(tc.local, tc.container)
		if err != nil {
			t.Fatalf("ResolveMode: %v", err)
		}
		if got != tc.want {
			t.Errorf("ResolveMode(%v, %v) = %q, want %q", tc.local, tc.container, got, tc.want)
		}
	}
}

func TestResolvePersistenceDir(t *testing.T) {
	cfg := &Config{PersistenceDir: "/data/nest"}
	env := func(kv map[string]string) func(string) string {
		return func(k string) string { return kv[k] }
	}
	if got := cfg.ResolvePersistenceDir(env(map[string]string{"NEST_PERSISTENCE_DIR": "/tmp/p"})); got != "/tmp/p" {
		t.Errorf("env: got %q", got)
	}
	if got := cfg.ResolvePersistenceDir(env(map[string]string{})); got != "/data/nest" {
		t.Errorf("config: got %q", got)
	}
	if got := (&Config{}).ResolvePersistenceDir(env(map[string]string{"HOME": "/home/u"})); got != "/home/u/nest/persistence" {
		t.Errorf("default: got %q, want /home/u/nest/persistence", got)
	}
}

func TestResolveCatalogURL(t *testing.T) {
	cfg := &Config{CatalogURL: "https://example.com/t.yaml"}
	env := func(kv map[string]string) func(string) string {
		return func(k string) string { return kv[k] }
	}
	if got := cfg.ResolveCatalogURL(env(map[string]string{"NEST_CATALOG_URL": "https://x"}), "pinned"); got != "https://x" {
		t.Errorf("env: got %q", got)
	}
	if got := cfg.ResolveCatalogURL(env(map[string]string{}), "pinned"); got != "https://example.com/t.yaml" {
		t.Errorf("config: got %q", got)
	}
	if got := (&Config{}).ResolveCatalogURL(env(map[string]string{}), "pinned"); got != "pinned" {
		t.Errorf("default: got %q, want pinned", got)
	}
}
