package config

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

func TestRedactedMasksSecret(t *testing.T) {
	c := Default()
	c.Proxmox.Token = "felhom-agent@pve!agent=b6547d9d-08ec-4f22-beb8-a551dc2cd69d"
	got := c.Redacted().Proxmox.Token
	if strings.Contains(got, "b6547d9d") {
		t.Fatalf("secret leaked in redacted token: %q", got)
	}
	if !strings.HasPrefix(got, "felhom-agent@pve!agent=") {
		t.Errorf("redacted token lost its public prefix: %q", got)
	}
	// The original must be untouched (Redacted returns a copy).
	if !strings.Contains(c.Proxmox.Token, "b6547d9d") {
		t.Errorf("Redacted mutated the original config")
	}
}

func TestValidate(t *testing.T) {
	c := Default()
	c.Proxmox.Node = "demo-felhom"
	c.Proxmox.Token = "felhom-agent@pve!agent=secret"
	if err := c.Validate(); err != nil {
		t.Fatalf("valid config rejected: %v", err)
	}
	c.Proxmox.Token = "no-bang-no-eq"
	if err := c.Validate(); err == nil {
		t.Errorf("malformed token accepted")
	}
}

func TestRedactedMasksHubKey(t *testing.T) {
	c := Default()
	c.Hub.APIKey = "hub-secret-abcdef"
	if got := c.Redacted().Hub.APIKey; got == "hub-secret-abcdef" || got == "" {
		t.Fatalf("hub key not masked: %q", got)
	}
	if !strings.Contains(c.Hub.APIKey, "abcdef") {
		t.Error("Redacted mutated the original hub key")
	}
}

func TestHubConfigValidate(t *testing.T) {
	base := HubConfig{URL: "https://hub.felhom.eu", HostID: "h1", APIKey: "k"}
	if err := base.Validate(); err != nil {
		t.Fatalf("valid hub config rejected: %v", err)
	}
	bad := []HubConfig{
		{HostID: "h", APIKey: "k"},                              // no URL
		{URL: "https://x", APIKey: "k"},                         // no host
		{URL: "https://x", HostID: "h"},                         // no key
		{URL: "http://hub.felhom.eu", HostID: "h", APIKey: "k"}, // http non-loopback
		{URL: "ftp://x", HostID: "h", APIKey: "k"},              // bad scheme
	}
	for i, h := range bad {
		if err := h.Validate(); err == nil {
			t.Errorf("case %d: expected validation error for %+v", i, h)
		}
	}
	// http is allowed for loopback (tests).
	if err := (HubConfig{URL: "http://127.0.0.1:8443", HostID: "h", APIKey: "k"}).Validate(); err != nil {
		t.Errorf("http loopback should be allowed: %v", err)
	}
}

func TestHubEnvOverlayAndDefaults(t *testing.T) {
	t.Setenv("FELHOM_AGENT_HUB_URL", "https://hub.example")
	t.Setenv("FELHOM_AGENT_HUB_HOST_ID", "env-host")
	t.Setenv("FELHOM_AGENT_HUB_API_KEY", "env-key")
	t.Setenv("FELHOM_AGENT_HUB_POLL_SECONDS", "120")
	cfg, err := Load("")
	if err != nil {
		t.Fatal(err)
	}
	if cfg.Hub.URL != "https://hub.example" || cfg.Hub.HostID != "env-host" || cfg.Hub.APIKey != "env-key" {
		t.Errorf("hub env overlay failed: %+v", cfg.Hub)
	}
	if cfg.Hub.PollSeconds != 120 {
		t.Errorf("poll seconds = %d, want 120", cfg.Hub.PollSeconds)
	}
	// withDefaults fills zero timeout.
	if (HubConfig{}).WithDefaults().TimeoutSeconds != 30 {
		t.Error("WithDefaults should set TimeoutSeconds=30")
	}
}

func TestLoadFileThenEnvOverride(t *testing.T) {
	dir := t.TempDir()
	path := filepath.Join(dir, "agent.json")
	if err := os.WriteFile(path, []byte(`{"proxmox":{"node":"file-node","token":"u@pve!t=filesecret"}}`), 0o600); err != nil {
		t.Fatal(err)
	}
	t.Setenv("FELHOM_AGENT_PROXMOX_NODE", "env-node")
	cfg, err := Load(path)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if cfg.Proxmox.Node != "env-node" {
		t.Errorf("env did not override node: %q", cfg.Proxmox.Node)
	}
	if cfg.Proxmox.Token != "u@pve!t=filesecret" {
		t.Errorf("token from file lost: %q", cfg.Proxmox.Token)
	}
	if cfg.Proxmox.Endpoint != "https://127.0.0.1:8006" {
		t.Errorf("default endpoint lost: %q", cfg.Proxmox.Endpoint)
	}
}
