package pkg

import (
	"testing"

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

func TestNewSettings_Commands(t *testing.T) {
	// We test that each mutually exclusive command sets the correct .cmd field

	defaultFile := utils.Content2File(t.TempDir()+"/pkglist", "pkg1\npkg2\n")

	t.Run("LIST_INSTALLED", func(t *testing.T) {
		args := []string{"test", "-" + LIST_INSTALLED_FLAG}
		s := newSettings(args, defaultFile)
		mustBeEqual(t, s.Cmd(), listInstalled)
	})

	t.Run("DEPENDEES", func(t *testing.T) {
		args := []string{"test", "-" + ROOT_FLAG, "rootPackage"}
		s := newSettings(args, defaultFile)
		mustBeEqual(t, s.Cmd(), dependees)
		mustBeEqual(t, s.Root(), "rootPackage")
	})

	t.Run("SHOW_VERSION", func(t *testing.T) {
		args := []string{"test", "-" + VERSION_FLAG}
		s := newSettings(args, defaultFile)
		mustBeEqual(t, s.Cmd(), showVersion)
	})

	t.Run("SEARCH", func(t *testing.T) {
		args := []string{"test", "-" + SEARCH_FLAG}
		s := newSettings(args, defaultFile)
		mustBeEqual(t, s.Cmd(), search)
	})

	t.Run("TRACKING", func(t *testing.T) {
		args := []string{"test", "-" + TRACK_FLAG}
		s := newSettings(args, defaultFile)
		mustBeEqual(t, s.Cmd(), tracking)
	})

	t.Run("VIEW", func(t *testing.T) {
		args := []string{"test", "-" + VIEW_FLAG}
		s := newSettings(args, defaultFile)
		mustBeEqual(t, s.Cmd(), view)
	})

	t.Run("VIEW_BUILD", func(t *testing.T) {
		args := []string{"test", "-" + VIEWBUILD_FLAG}
		s := newSettings(args, defaultFile)
		mustBeEqual(t, s.Cmd(), viewBuild)
	})

	t.Run("DEFAULT_UPGRADE", func(t *testing.T) {
		// If none of the “command” flags are set and root is empty => UPGRADE
		args := []string{"test"}
		s := newSettings(args, defaultFile)
		mustBeEqual(t, s.Cmd(), upgrade)
	})
}

func TestNewSettings_MutuallyExclusiveCommands(t *testing.T) {
	// Try passing both -v and -search => expect panic
	defaultFile := utils.Content2File(t.TempDir()+"/pkglist", "pkg1\npkg2\n")
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("Expected panic if multiple command flags are used, but got none")
		}
	}()
	args := []string{"test", "-" + VIEW_FLAG, "-" + SEARCH_FLAG}
	_ = newSettings(args, defaultFile)
	t.Errorf("Should have panicked before this line") // For clarity
}

func TestNewSettings_FileFlagAndPositionalArgs(t *testing.T) {
	defaultFile := utils.Content2File(t.TempDir()+"/pkglist", "pkg1\npkg2\n")
	t.Run("PanicIfFileFlagAndPositionalArgsUsedTogether", func(t *testing.T) {
		// If we pass -f something AND positional arguments are also given,
		// we expect a panic if the filePtr != DefaultPkgFile
		defer func() {
			if r := recover(); r == nil {
				t.Errorf("Expected panic if both -f customFile and positional arguments used, but got none")
			}
		}()
		args := []string{"test", "-" + FILE_FLAG, "someOtherFile", "pkg1", "pkg2"}
		_ = newSettings(args, defaultFile)
		t.Errorf("Should have panicked before this line")
	})

	t.Run("NoPanicIfUsingDefaultFileWithoutPositionalArgs", func(t *testing.T) {
		// This should be fine: no positional args => we load from defaultFile
		args := []string{"test", "-" + FILE_FLAG, defaultFile}
		s := newSettings(args, defaultFile)
		if len(s.PkgNames()) == 2 {
			// By default, if pkgNames is empty, we read from file
		} else {
			t.Errorf("Expected no pkgNames if none are specified, got %v", s.PkgNames())
		}
	})
}

func TestNewSettings_BooleanFlags(t *testing.T) {
	defaultFile := utils.Content2File(t.TempDir()+"/pkglist", "pkg1\npkg2\n")
	t.Run("MD5Flag", func(t *testing.T) {
		// By default, checkMD5Sum = true, but if we pass -md5 then it's toggled to false
		args := []string{"test", "-" + MD5_FLAG}
		s := newSettings(args, defaultFile)
		if s.CheckMD5Sum() {
			t.Errorf("Expected checkMD5Sum to be false, got true (md5 flag was set)")
		}
	})

	t.Run("NoDeps", func(t *testing.T) {
		args := []string{"test", "-" + NO_DEPS_FLAG}
		s := newSettings(args, defaultFile)
		if !s.NoDeps() {
			t.Errorf("Expected noDeps to be true, got false")
		}
	})

	t.Run("FilterInstalled", func(t *testing.T) {
		// The code has filterInstalled as !*filterInstalledPtr
		// meaning the default is true, but if we pass the flag, we flip it.
		args := []string{"test", "-" + FILTERINSTALLED_FLAG}
		s := newSettings(args, defaultFile)
		if s.FilterInstalled() {
			t.Errorf("Expected filterInstalled to be false, got true")
		}
	})

	t.Run("RespectGreylist", func(t *testing.T) {
		// The code sets s.respectGreylist = !*skipGreylistPtr
		// If we pass -respect-greylist (skipGreylistPtr = true), then respectGreylist = false
		args := []string{"test", "-" + RESPECTGREYLIST_FLAG}
		s := newSettings(args, defaultFile)
		if s.RespectGreylist() {
			t.Errorf("Expected respectGreylist=false, got true")
		}
	})

	t.Run("Update", func(t *testing.T) {
		args := []string{"test", "-" + UPDATE_FLAG}
		s := newSettings(args, defaultFile)
		if !s.Update() {
			t.Errorf("Expected update=true, got false")
		}
	})

	t.Run("Yes", func(t *testing.T) {
		args := []string{"test", "-" + YES_FLAG}
		s := newSettings(args, defaultFile)
		if !s.Yes() {
			t.Errorf("Expected yes=true, got false")
		}
	})
}

func TestNewSettings_UpdateBlacklist(t *testing.T) {
	// s.updateBlacklist gets set if:
	//   (filePtr == DefaultPkgFile) && pkgs_from_file && !noDepsPtr
	// That means:
	//   1) -f not used or is defaultFile
	//   2) pkgNames are empty => loaded from file => pkgs_from_file = true
	//   3) -no-deps not passed

	defaultFile := utils.Content2File(t.TempDir()+"/pkglist", "pkg1\npkg2\n")

	t.Run("UpdateBlacklist_True", func(t *testing.T) {
		args := []string{"test"} // no commands => upgrade, no file override
		// No positional arguments => pkgs_from_file is true
		// filePtr == DefaultPkgFile => let's say defaultFile
		s := newSettings(args, defaultFile)
		if !s.UpdateBlacklist() {
			t.Errorf("Expected updateBlacklist=true under these conditions, got false")
		}
	})

	t.Run("UpdateBlacklist_False_When_CustomFile", func(t *testing.T) {
		// If we use -f customFile, then (filePtr == DefaultPkgFile) is false
		// => s.updateBlacklist should be false
		customFile := utils.Content2File(t.TempDir()+"/pkglist", "pkg1\npkg2\n")
		args := []string{"test", "-" + FILE_FLAG, customFile}
		s := newSettings(args, defaultFile)
		if s.UpdateBlacklist() {
			t.Errorf("Expected updateBlacklist=false when using -f customFile, got true")
		}
	})

	t.Run("UpdateBlacklist_False_When_PositionalArgs", func(t *testing.T) {
		// If we pass positional arguments => pkgs_from_file = false
		// => s.updateBlacklist = false
		args := []string{"test", "pkg1", "pkg2"}
		s := newSettings(args, defaultFile)
		if s.UpdateBlacklist() {
			t.Errorf("Expected updateBlacklist=false when positional arguments are provided, got true")
		}
	})

	t.Run("UpdateBlacklist_False_When_NoDeps", func(t *testing.T) {
		args := []string{"test", "-" + NO_DEPS_FLAG}
		s := newSettings(args, defaultFile)
		if s.UpdateBlacklist() {
			t.Errorf("Expected updateBlacklist=false when noDeps is set, got true")
		}
	})
}

func TestNewSettings_PkgNamesAndBuildOptions(t *testing.T) {
	// Suppose we pass multiple packages with build options

	defaultFile := utils.Content2File(t.TempDir()+"/pkglist", "pkg1\npkg2\n")

	args := []string{"test", "pkg1", "OPT1=val1", "pkg2", "OPT2=val2"}
	s := newSettings(args, defaultFile)
	pkgs := s.PkgNames()

	mustBeEqual(t, len(pkgs), 2)
	mustBeEqual(t, pkgs[0], "pkg1")
	mustBeEqual(t, pkgs[1], "pkg2")
	mustBeEqualStringSlices(t, s.BuildOptions()["pkg1"], []string{"OPT1=val1"})
	mustBeEqualStringSlices(t, s.BuildOptions()["pkg2"], []string{"OPT2=val2"})
}

func TestPkgNamesAndBuildOptions(t *testing.T) {
	input := []string{"foo", "bar=baz"}
	names, buildOptions := pkgNamesAndBuildOptions(input)
	if len(names) != 1 || names[0] != "foo" {
		t.Error("pkgNamesAndBuildOptions() returned incorrect package names")
	}
	if len(buildOptions) != 1 || buildOptions["foo"][0] != "bar=baz" {
		t.Error("pkgNamesAndBuildOptions() returned incorrect build options")
	}
	t.Log("pkgNamesAndBuildOptions() test passed with names:", names, "and build options:", buildOptions)
}
