package utils

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

func TestMd5str(t *testing.T) {
	cases := []struct {
		in   string
		want string
	}{
		{"", "d41d8cd98f00b204e9800998ecf8427e"},
		{"hello", "5d41402abc4b2a76b9719d911017c592"},
		{"test", "098f6bcd4621d373cade4e832627b4f6"},
	}
	for _, c := range cases {
		got := Md5str(c.in)
		if got != c.want {
			t.Errorf("Md5str(%q) = %s, want %s", c.in, got, c.want)
		}
	}
}

func TestMd5str_Consistency(t *testing.T) {
	h1 := Md5str("same")
	h2 := Md5str("same")
	if h1 != h2 {
		t.Error("Md5str should be deterministic")
	}
}

func TestArrayUnique(t *testing.T) {
	in := []string{"a", "b", "a", "c", "b", "d"}
	got := ArrayUnique(in)
	if len(got) != 4 {
		t.Fatalf("expected 4, got %d: %v", len(got), got)
	}
	seen := map[string]bool{}
	for _, v := range got {
		if seen[v] {
			t.Errorf("duplicate found: %s", v)
		}
		seen[v] = true
	}
}

func TestArrayUnique_Empty(t *testing.T) {
	got := ArrayUnique([]string{})
	if len(got) != 0 {
		t.Errorf("expected empty, got %v", got)
	}
}

func TestArrayUnique_Single(t *testing.T) {
	got := ArrayUnique([]string{"only"})
	if len(got) != 1 || got[0] != "only" {
		t.Errorf("expected [only], got %v", got)
	}
}

func TestArrayUnique_AllSame(t *testing.T) {
	got := ArrayUnique([]string{"x", "x", "x"})
	if len(got) != 1 || got[0] != "x" {
		t.Errorf("expected [x], got %v", got)
	}
}

func TestExpandPath_Relative(t *testing.T) {
	got, err := ExpandPath("foo/bar")
	if err != nil {
		t.Fatal(err)
	}
	if got == "" {
		t.Error("expected non-empty path")
	}
	// should be absolute
	if got[0] != '/' {
		t.Errorf("expected absolute path, got %s", got)
	}
}

func TestExpandPath_Tilde(t *testing.T) {
	got, err := ExpandPath("~/test")
	if err != nil {
		t.Fatal(err)
	}
	if got == "" {
		t.Error("expected non-empty path")
	}
	// should not contain ~
	for _, c := range got {
		if c == '~' {
			t.Error("path should not contain ~")
			break
		}
	}
}

func TestFetch_Success(t *testing.T) {
	body := "hello world"
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if ua := r.Header.Get("User-Agent"); ua != "TestUA" {
			t.Errorf("expected User-Agent 'TestUA', got '%s'", ua)
		}
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(body))
	}))
	defer srv.Close()

	data, err := Fetch(srv.URL, "TestUA", 5*time.Second)
	if err != nil {
		t.Fatal(err)
	}
	if string(data) != body {
		t.Errorf("expected '%s', got '%s'", body, string(data))
	}
}

func TestFetch_NonOK(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
	}))
	defer srv.Close()

	_, err := Fetch(srv.URL, "", 5*time.Second)
	if err == nil {
		t.Error("expected error for non-200 status")
	}
}

func TestFetch_EmptyUserAgent(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("ok"))
	}))
	defer srv.Close()

	data, err := Fetch(srv.URL, "", 5*time.Second)
	if err != nil {
		t.Fatal(err)
	}
	if string(data) != "ok" {
		t.Errorf("expected 'ok', got '%s'", string(data))
	}
}

func TestFetch_InvalidURL(t *testing.T) {
	_, err := Fetch("http://[::1]:named", "", 1*time.Second)
	if err == nil {
		t.Error("expected error for invalid URL")
	}
}
