package must

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

func TestMkdir(t *testing.T) {
	td := t.TempDir()
	testDir := td + "/foo"
	Mkdir(testDir)
	if _, err := os.Stat(testDir); os.IsNotExist(err) {
		t.Error("Mkdir() did not create the directory")
	}
}

func TestReadChar(t *testing.T) {
	res := ReadChar(strings.NewReader("foo"))
	if res != 'f' {
		t.Error("ReadChar() did not return the correct character")
	}
}

func TestReadFile(t *testing.T) {
	td := t.TempDir()
	f := Create(td + "/foo")
	defer f.Close()
	expected := "bar"
	f.WriteString(expected)
	f.Sync()
	got := ReadFile(f.Name())
	if string(got) != expected {
		t.Error("ReadFile() did not return the correct content")
	}
}

func TestOpen(t *testing.T) {
	td := t.TempDir()
	f := Create(td + "/foo")
	defer f.Close()
	if Open(f.Name()).Name() != f.Name() {
		t.Error("Open() did not return the correct file")
	}
}

func TestSetEnvIfNotSet(t *testing.T) {
	if SetEnvIfNotSet("FOO", "bar") != os.Getenv("FOO") {
		t.Error("SetEnvIfNotSet() did not return the correct value")
	}
	if SetEnvIfNotSet("HOME", "bar") != os.Getenv("HOME") || os.Getenv("HOME") == "bar" {
		t.Error("SetEnvIfNotSet() did not return the correct value")
	}
	t.Log("SetEnvIfNotSet() test passed with value:", SetEnvIfNotSet("FOO", "bar"))
}

func TestMustPanic(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Error("Must() did not panic")
		}
	}()
	Must(errors.New("foo"))
}

func TestCopy(t *testing.T) {
	var (
		td        = t.TempDir()
		expected  = "foo"
		src, dest = Create(td + "/src"), Create(td + "/dest")
		got       = make([]byte, len(expected))
	)
	defer src.Close()
	defer dest.Close()
	src.WriteString(expected)
	src.Seek(0, 0)
	Copy(src, dest)
	dest.Seek(0, 0)
	dest.Read(got)
	if string(got) != expected {
		t.Error("Expected", expected, ", got", got)
	}
}

func TestSymlink(t *testing.T) {
	td := t.TempDir()
	src := td + "/src"
	dest := td + "/dest"
	Create(src).Close()
	Symlink(src, dest)
	if _, err := os.Lstat(dest); err != nil {
		t.Error("Symlink() did not create the symlink")
	}
}

func TestReadDir(t *testing.T) {
	td := t.TempDir()
	files := []string{"bar", "baz", "foo"}
	for _, file := range files {
		Create(td + "/" + file).Close()
	}
	readFiles := ReadDir(td)
	if len(readFiles) != len(files) {
		t.Error("ReadDir() did not return the correct number of files")
	}
	for i, f := range readFiles {
		if f.Name() != files[i] {
			t.Error("Expected", files[i], ", got", f.Name())
		}
	}
}

func TestModTime(t *testing.T) {
	td := t.TempDir()
	f := Create(td + "/foo")
	defer f.Close()
	for _, file := range ReadDir(td) {
		if time.Time.Equal(ModTime(file), time.Time{}) {
			t.Error("ModTime() did not return the correct time")
		}
	}
}

func TestContent2File(t *testing.T) {
	td := t.TempDir()
	content := "test content"
	filename := td + "/testfile.txt"
	Content2File(filename, content)
	got := ReadFile(filename)
	if string(got) != content {
		t.Error("Content2File() did not write the correct content to file")
	}
}

func TestChmod(t *testing.T) {
	td := t.TempDir()
	f := Create(filepath.Join(td, "foo"))
	for _, mode := range []os.FileMode{0644, 0755, 0777} {
		t.Run("Chmod_"+mode.String(), func(t *testing.T) {
			Chmod(f.Name(), mode)
			info, err := os.Stat(f.Name())
			if err != nil {
				t.Error("Chmod() failed to stat file:", err)
			}
			if info.Mode().Perm() != mode {
				t.Error("Chmod() did not set the correct permissions, expected",
					mode, ", got", info.Mode().Perm())
			}
		})
	}
}
