package fuse

import (
	"context"
	"errors"
	"os"
	"time"
)

var (
	ErrNotExists    = os.ErrNotExist
	ErrExists       = os.ErrExist
	ErrNotEmpty     = errors.New("directory not empty")
	ErrPermission   = os.ErrPermission
	ErrIOError      = errors.New("I/O error")
	ErrNotSupported = errors.New("not supported")
)

type Fs interface {
	Stats() FsStats
	Root() FsDir
}

type FsStats struct {
	TotalDataBytes   int64 // 存储的总数据量
	TotalObjectCount int64 // 存储的总对象数量
}

type FsEntry interface {
	Name() string
	Size() int64
	Perm() os.FileMode
	ModTime() time.Time
	IsDir() bool
}

type FsDir interface {
	FsEntry

	// 如果不存在，应该返回ErrNotExists
	SetModTime(time time.Time) error
	Child(ctx context.Context, name string) (FsEntry, error)
	Children(ctx context.Context) ([]FsEntry, error)
	ReadChildren() (DirReader, error)
	NewDir(ctx context.Context, name string) (FsDir, error)
	NewFile(ctx context.Context, name string, flags uint32) (FileHandle, uint32, error)
	RemoveChild(ctx context.Context, name string) error
	MoveChild(ctx context.Context, oldName string, newName string, newParent FsDir) error
}

type FsFile interface {
	FsEntry

	Truncate(size uint64) error
	SetModTime(time time.Time) error
	Open(flags uint32) (FileHandle, uint32, error)
}

type DirReader interface {
	HasNext() bool
	Next(n int) ([]FsEntry, error)
	Close()
}

type FileHandle interface {
	Entry() FsFile
	ReadAt(buf []byte, off int64) (int, error)
	WriteAt(buf []byte, off int64) (int, error)
	// 按GPT解释，Flush会在文件描述符被Close时调用，目的是将用户缓冲区的数据送到内核缓冲区。
	// 要注意的是，可以通过dup函数创建多个文件描述符，而它们都引用这个文件句柄，所以要小心Flush是可能会被多次调用的。
	Flush() error
	// 而这个函数是将内核缓冲区的数据写入到磁盘
	Sync() error
	// 这个函数只有在句柄的所有引用都被释放时才会被调用，目的是释放内核资源
	Close() error
}
