package networking

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

const sampleHosts = `# static table
127.0.0.1	localhost
::1		localhost ip6-localhost
192.168.1.10	server server.local  # the box

`

func TestParseHosts(t *testing.T) {
	got := parseHosts(sampleHosts)
	want := []HostEntry{
		{IP: "127.0.0.1", Hostnames: []string{"localhost"}},
		{IP: "::1", Hostnames: []string{"localhost", "ip6-localhost"}},
		{IP: "192.168.1.10", Hostnames: []string{"server", "server.local"}},
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("parseHosts:\n got %+v\nwant %+v", got, want)
	}
}

func TestUpsertAndDeleteHost(t *testing.T) {
	path := filepath.Join(t.TempDir(), "hosts")
	if err := os.WriteFile(path, []byte(sampleHosts), 0644); err != nil {
		t.Fatal(err)
	}
	old := hostsFile
	hostsFile = path
	defer func() { hostsFile = old }()

	// Update an existing IP — comments and other lines must survive.
	if err := upsertHost("192.168.1.10", []string{"web", "web.local"}); err != nil {
		t.Fatal(err)
	}
	data, _ := os.ReadFile(path)
	if !strings.Contains(string(data), "# static table") || !strings.Contains(string(data), "ip6-localhost") {
		t.Errorf("upsert clobbered other lines:\n%s", data)
	}
	entries := parseHosts(string(data))
	if e := findHost(entries, "192.168.1.10"); e == nil || !reflect.DeepEqual(e.Hostnames, []string{"web", "web.local"}) {
		t.Errorf("upsert did not update entry: %+v", entries)
	}

	// Add a new IP.
	if err := upsertHost("10.0.0.5", []string{"db"}); err != nil {
		t.Fatal(err)
	}
	entries = parseHosts(mustRead(t, path))
	if findHost(entries, "10.0.0.5") == nil {
		t.Errorf("upsert did not append new entry: %+v", entries)
	}

	// Delete it again.
	removed, err := deleteHost("10.0.0.5")
	if err != nil || !removed {
		t.Fatalf("delete failed: removed=%v err=%v", removed, err)
	}
	if findHost(parseHosts(mustRead(t, path)), "10.0.0.5") != nil {
		t.Error("entry still present after delete")
	}

	// Deleting a missing IP reports not-removed.
	if removed, _ := deleteHost("8.8.8.8"); removed {
		t.Error("expected removed=false for missing IP")
	}
}

func findHost(entries []HostEntry, ip string) *HostEntry {
	for i := range entries {
		if entries[i].IP == ip {
			return &entries[i]
		}
	}
	return nil
}

func mustRead(t *testing.T, path string) string {
	t.Helper()
	data, err := os.ReadFile(path)
	if err != nil {
		t.Fatal(err)
	}
	return string(data)
}
