package must

// Description: This file contains the wrapper functions for the os and io package.

import (
	"io"
	"os"
	"time"
)

// Mkdir creates a directory at the specified path, including all necessary
// parent directories. It is a wrapper around os.MkdirAll which panics if the
// operation fails.
func Mkdir(path string) { Must(os.MkdirAll(path, 0755)) }

// Symlink creates a symbolic link named newname that points to oldname.
// It is a wrapper around os.Symlink which panics if the operation fails.
func Symlink(oldname, newname string) { Must(os.Symlink(oldname, newname)) }

// SetEnvIfNotSet checks if the environment variable envvar is set. If it is
// not, it sets the variable to the provided fallback value and returns that
// value.
func SetEnvIfNotSet(envvar, fallback string) string {
	value := os.Getenv(envvar)
	if value == "" {
		os.Setenv(envvar, fallback)
		return fallback
	}
	return value
}

// Copy reads from src and writes to dest. It panics if the operation fails.
func Copy(src io.Reader, dest io.Writer) {
	_, err := io.Copy(dest, src)
	Must(err)
}

// ReadChar reads a single byte from the provided io.Reader and returns it.
// It panics if the read operation fails.
func ReadChar(r io.Reader) byte {
	char := make([]byte, 1)
	_, err := r.Read(char)
	Must(err)
	return char[0]
}

// Create creates a new file with the specified name. If the file already exists,
// it truncates the file to zero length. It is a wrapper around os.Create and
// panics if the operation fails.
func Create(file string) *os.File {
	f, err := os.Create(file)
	Must(err)
	return f
}

// Content2File creates a new file with the specified name and writes the
// provided content to it.
func Content2File(fname, content string) string {
	f := Create(fname)
	defer f.Close()
	f.WriteString(content)
	return fname
}

// Open opens a file with the specified name for reading. It is a wrapper around
// os.Open and panics if the operation fails.
func Open(file string) *os.File {
	f, err := os.Open(file)
	Must(err)
	return f
}

// ReadDir reads the contents of the directory at the specified path and
// returns a slice of os.DirEntry. It is a wrapper around os.ReadDir and
// panics if the operation fails.
func ReadDir(path string) []os.DirEntry {
	files, err := os.ReadDir(path)
	Must(err)
	return files
}

// ReadFile reads the contents of the file at the specified path and returns
// it as a byte slice. It is a wrapper around os.ReadFile and panics if the
// operation fails.
func ReadFile(path string) []byte {
	data, err := os.ReadFile(path)
	Must(err)
	return data
}

// ModTime returns the modification time of the file represented by the
// os.DirEntry. It is a wrapper around os.FileInfo.ModTime and panics if
// the operation fails.
func ModTime(file os.DirEntry) time.Time {
	info, err := file.Info()
	Must(err)
	return info.ModTime()
}

// Chmod changes the file mode of the file at the specified path to the
// specified mode. It is a wrapper around os.Chmod and panics if the
// operation fails.
func Chmod(path string, mode os.FileMode) { Must(os.Chmod(path, mode)) }

// Must is a utility function that panics if the provided error is not nil.
func Must(err error) {
	if err != nil {
		panic(err)
	}
}
