// file: repomap_test.go
package sboRepo

import (
	"path/filepath"
	"testing"

	"gitlab.com/M0M097/pkg/lib/utils"
)

// This test showcases how to create a real directory structure in a temp dir.
func TestNewRepoMap(t *testing.T) {
	tmpDir := t.TempDir()

	/* Let's create the following structure:
	   tmpDir/
	      pkgdir1/ (dir)
	          pkgA (file)
	          pkgB (file)
	      pkgdir2/ (dir)
	          pkgC (file)
	      notADir (file) */

	pkgdir1 := filepath.Join(tmpDir, "pkgdir1")
	pkgdir2 := filepath.Join(tmpDir, "pkgdir2")

	utils.Mkdir(pkgdir1)
	utils.Mkdir(pkgdir2)

	// Create empty files
	utils.Create(filepath.Join(pkgdir1, "pkgA"))
	utils.Create(filepath.Join(pkgdir1, "pkgB"))
	utils.Create(filepath.Join(pkgdir2, "pkgC"))

	// A file in tmpDir that should be ignored, because !IsDir()
	utils.Create(filepath.Join(tmpDir, "notADir"))

	// Now invoke NewRepoMap on tmpDir
	repo := NewRepoMap(tmpDir)

	if len(repo) != 3 {
		t.Fatalf("expected 3 packages in repo, got %d", len(repo))
	}

	cases := []struct {
		pkgName string
		wantDir string
	}{
		{"pkgA", pkgdir1},
		{"pkgB", pkgdir1},
		{"pkgC", pkgdir2},
	}
	for _, c := range cases {
		pkg, ok := repo[c.pkgName]
		if !ok {
			t.Errorf("expected package %q in repo map, but not found", c.pkgName)
			continue
		}
		if pkg.path != c.wantDir {
			t.Errorf("expected path %q for pkg %q, got %q", c.wantDir, c.pkgName, pkg.path)
		}
	}
}

func TestRepoMapGet(t *testing.T) {
	rm := dummyRepoMap()

	// Retrieve an existing package
	got := rm.Get("foo")
	if got.Name() != "foo" {
		t.Errorf("expected 'foo', got '%s'", got.Name())
	}

	// Test that requesting a non-existing package panics
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("expected a panic for non-existing package, got no panic")
		}
	}()
	_ = rm.Get("foobar")
}

func TestRepoMapContains(t *testing.T) {
	rm := dummyRepoMap()

	if !rm.Contains("foo") {
		t.Errorf("expected Contains(foo) to be true")
	}
	if rm.Contains("foobar") {
		t.Errorf("expected Contains(baz) to be false")
	}
}

func TestRepoMap_ProcessList(t *testing.T) {
	// 1) Create two packages, p1 and p2, with .info files that have no real dependencies.
	p1 := &Package{name: "p1"}
	p2 := &Package{name: "p2"}

	// If you have a helper that lets you specify REQUIRES, set it to an empty line or %README%.
	// Otherwise, just use createPkgTestfiles(...) if it produces a trivial REQUIRES by default.
	createPkgTestfilesWithRequires(p1, t, "%README%") // or just ""
	createPkgTestfilesWithRequires(p2, t, "%README%")

	// 2) Put them into the RepoMap.
	rm := RepoMap{
		"p1": p1,
		"p2": p2,
	}

	// 3) Call ProcessList with pkgNames = [p1, p2].
	head := rm.ProcessList([]string{"p1", "p2"})

	// 4) The returned head is a sentinel; actual packages start at head.next.
	if head.next == nil || head.next.name != "p1" {
		t.Fatalf("Expected first package to be 'p1', got %v", head.next)
	}
	if head.next.next == nil || head.next.next.name != "p2" {
		t.Fatalf("Expected second package to be 'p2', got %v", head.next.next)
	}

	// 5) Check there isn’t a third package.
	if head.next.next.next != nil {
		t.Errorf("Expected exactly two packages, found more.")
	}
}

func TestRepoMapPkgNames2List(t *testing.T) {
	rm := dummyRepoMap()
	head := rm.PkgNames2List([]string{"foo", "bar", "baz"})
	// The list is head -> foo -> bar -> baz

	if head.next == nil || head.next.Name() != "foo" {
		t.Errorf("expected first item to be 'foo', got %v", head.next)
	}
	if head.next.next == nil || head.next.next.Name() != "bar" {
		t.Errorf("expected second item to be 'bar', got %v", head.next.next)
	}
	if head.next.next.next == nil || head.next.next.next.Name() != "baz" {
		t.Errorf("expected third item to be 'baz', got %v", head.next.next.next)
	}
}

func TestIterOver(t *testing.T) {
	res := make([]string, 0)
	rm := dummyRepoMap()
	rm.IterOver([]string{"foo", "bar", "baz"},
		func(pkg *Package) { res = append(res, pkg.Name()) })
	if len(res) != 3 {
		t.Fatalf("expected 3 items, got %d", len(res))
	}
	if res[0] != "foo" || res[1] != "bar" || res[2] != "baz" {
		t.Errorf("expected foo, bar, baz, got %v", res)
	}
}

func dummyRepoMap() RepoMap {
	return RepoMap{
		"foo": &Package{name: "foo"},
		"bar": &Package{name: "bar"},
		"baz": &Package{name: "baz"},
	}
}
