package filesystem

import (
	"errors"
	"io/fs"
	"os"
	"time"

	"github.com/kopia/kopia/internal/ospath"
)

// realOS is an implementation of osInterface that uses real operating system calls.
type realOS struct{}

func (realOS) Open(fname string) (osReadFile, error) {
	f, err := os.Open(ospath.SafeLongFilename(fname))
	if err != nil {
		//nolint:wrapcheck
		return nil, err
	}

	return f, nil
}

func (realOS) IsNotExist(err error) bool { return os.IsNotExist(err) }

func (realOS) IsExist(err error) bool { return os.IsExist(err) }

func (realOS) IsPathSeparator(c byte) bool { return os.IsPathSeparator(c) }

func (realOS) Rename(oldname, newname string) error {
	//nolint:wrapcheck
	return os.Rename(ospath.SafeLongFilename(oldname), ospath.SafeLongFilename(newname))
}

func (realOS) ReadDir(dirname string) ([]fs.DirEntry, error) {
	//nolint:wrapcheck
	return os.ReadDir(ospath.SafeLongFilename(dirname))
}

func (realOS) IsPathError(err error) bool {
	var pe *os.PathError

	return errors.As(err, &pe)
}

func (realOS) IsLinkError(err error) bool {
	var pe *os.LinkError

	return errors.As(err, &pe)
}

func (realOS) Remove(fname string) error {
	//nolint:wrapcheck
	return os.Remove(ospath.SafeLongFilename(fname))
}

func (realOS) Stat(fname string) (os.FileInfo, error) {
	//nolint:wrapcheck
	return os.Stat(ospath.SafeLongFilename(fname))
}

func (realOS) CreateNewFile(fname string, perm os.FileMode) (osWriteFile, error) {
	//nolint:wrapcheck
	return os.OpenFile(ospath.SafeLongFilename(fname), os.O_CREATE|os.O_EXCL|os.O_WRONLY, perm)
}

func (realOS) Mkdir(fname string, mode os.FileMode) error {
	//nolint:wrapcheck
	return os.Mkdir(ospath.SafeLongFilename(fname), mode)
}

func (realOS) MkdirAll(fname string, mode os.FileMode) error {
	//nolint:wrapcheck
	return os.MkdirAll(ospath.SafeLongFilename(fname), mode)
}

func (realOS) Chtimes(fname string, atime, mtime time.Time) error {
	//nolint:wrapcheck
	return os.Chtimes(ospath.SafeLongFilename(fname), atime, mtime)
}

func (realOS) Geteuid() int {
	return os.Geteuid()
}

func (realOS) Chown(fname string, uid, gid int) error {
	//nolint:wrapcheck
	return os.Chown(ospath.SafeLongFilename(fname), uid, gid)
}

var _ osInterface = realOS{}
