package helpers

import (
	"context"
	"io/fs"

	"git.kmsign.ru/royalcat/tstor/pkg/go-nfs"
	"github.com/go-git/go-billy/v5"
)

func WrapBillyFS(bf billy.Filesystem) nfs.Filesystem {
	return &wrapFS{
		Filesystem: bf,
	}
}

type wrapFS struct {
	billy.Filesystem
}

var _ nfs.Filesystem = (*wrapFS)(nil)

// Create implements Filesystem.
// Subtle: this method shadows the method (Filesystem).Create of MemFS.Filesystem.
func (m *wrapFS) Create(ctx context.Context, filename string) (nfs.File, error) {
	bf, err := m.Filesystem.Create(filename)
	if err != nil {
		return nil, err
	}
	return &wrapFile{bf}, nil
}

// Lstat implements Filesystem.
// Subtle: this method shadows the method (Filesystem).Lstat of MemFS.Filesystem.
func (m *wrapFS) Lstat(ctx context.Context, filename string) (fs.FileInfo, error) {
	return m.Filesystem.Lstat(filename)
}

// MkdirAll implements Filesystem.
// Subtle: this method shadows the method (Filesystem).MkdirAll of MemFS.Filesystem.
func (m *wrapFS) MkdirAll(ctx context.Context, filename string, perm fs.FileMode) error {
	return m.Filesystem.MkdirAll(filename, perm)
}

// Open implements Filesystem.
// Subtle: this method shadows the method (Filesystem).Open of MemFS.Filesystem.
func (m *wrapFS) Open(ctx context.Context, filename string) (nfs.File, error) {
	bf, err := m.Filesystem.Open(filename)
	if err != nil {
		return nil, err
	}
	return WrapFile(bf), nil
}

// OpenFile implements Filesystem.
// Subtle: this method shadows the method (Filesystem).OpenFile of MemFS.Filesystem.
func (m *wrapFS) OpenFile(ctx context.Context, filename string, flag int, perm fs.FileMode) (nfs.File, error) {
	bf, err := m.Filesystem.OpenFile(filename, flag, perm)
	if err != nil {
		return nil, err
	}
	return WrapFile(bf), nil
}

// ReadDir implements Filesystem.
// Subtle: this method shadows the method (Filesystem).ReadDir of MemFS.Filesystem.
func (m *wrapFS) ReadDir(ctx context.Context, path string) ([]fs.FileInfo, error) {
	return m.Filesystem.ReadDir(path)
}

// Readlink implements Filesystem.
// Subtle: this method shadows the method (Filesystem).Readlink of MemFS.Filesystem.
func (m *wrapFS) Readlink(ctx context.Context, link string) (string, error) {
	return m.Filesystem.Readlink(link)
}

// Remove implements Filesystem.
// Subtle: this method shadows the method (Filesystem).Remove of MemFS.Filesystem.
func (m *wrapFS) Remove(ctx context.Context, filename string) error {
	return m.Filesystem.Remove(filename)
}

// Rename implements Filesystem.
// Subtle: this method shadows the method (Filesystem).Rename of MemFS.Filesystem.
func (m *wrapFS) Rename(ctx context.Context, oldpath string, newpath string) error {
	return m.Filesystem.Rename(oldpath, newpath)
}

// Stat implements Filesystem.
// Subtle: this method shadows the method (Filesystem).Stat of MemFS.Filesystem.
func (m *wrapFS) Stat(ctx context.Context, filename string) (fs.FileInfo, error) {
	return m.Filesystem.Stat(filename)
}

// Symlink implements Filesystem.
// Subtle: this method shadows the method (Filesystem).Symlink of MemFS.Filesystem.
func (m *wrapFS) Symlink(ctx context.Context, target string, link string) error {
	return m.Filesystem.Symlink(target, link)
}

func WrapFile(bf billy.File) nfs.File {
	return &wrapFile{File: bf}
}

type wrapFile struct {
	billy.File
}

var _ nfs.File = (*wrapFile)(nil)

// Close implements File.
// Subtle: this method shadows the method (File).Close of MemFile.File.
func (m *wrapFile) Close(ctx context.Context) error {
	return m.File.Close()
}

// Lock implements File.
// Subtle: this method shadows the method (File).Lock of MemFile.File.
func (m *wrapFile) Lock() error {
	return m.File.Lock()
}

// Name implements File.
// Subtle: this method shadows the method (File).Name of MemFile.File.
func (m *wrapFile) Name() string {
	return m.File.Name()
}

// Truncate implements File.
// Subtle: this method shadows the method (File).Truncate of memFile.File.
func (m *wrapFile) Truncate(ctx context.Context, size int64) error {
	return m.File.Truncate(size)
}

// Read implements File.
// Subtle: this method shadows the method (File).Read of MemFile.File.
func (m *wrapFile) Read(ctx context.Context, p []byte) (n int, err error) {
	return m.File.Read(p)
}

// ReadAt implements File.
// Subtle: this method shadows the method (File).ReadAt of MemFile.File.
func (m *wrapFile) ReadAt(ctx context.Context, p []byte, off int64) (n int, err error) {
	return m.File.ReadAt(p, off)
}

// Unlock implements File.
// Subtle: this method shadows the method (File).Unlock of MemFile.File.
func (m *wrapFile) Unlock() error {
	return m.File.Unlock()
}

// Write implements File.
// Subtle: this method shadows the method (File).Write of MemFile.File.
func (m *wrapFile) Write(ctx context.Context, p []byte) (n int, err error) {
	return m.File.Write(p)
}