package kubelwagen

import (
	"fmt"
	"time"

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
)

type WsFsFile struct {
	nodefs.File
	h  int
	fs *WsFs
}

func newWsFsFile(handle int, fs *WsFs) *WsFsFile {
	return &WsFsFile{
		File: nodefs.NewDefaultFile(),
		h:    handle,
		fs:   fs,
	}
}
func (f *WsFsFile) String() string {
	return fmt.Sprintf("WsFsFile:%d", f.h)
}

func (f *WsFsFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
	r := Request{
		Method:     MethodFileRead,
		FileHandle: f.h,
		Offset:     off,
		Size:       uint32(len(buf)),
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return nil, fuse.ENOSYS
	}
	return fuse.ReadResultData(resp.Data), resp.Code
}

func (f *WsFsFile) Write(data []byte, off int64) (uint32, fuse.Status) {
	r := Request{
		Method:     MethodFileWrite,
		FileHandle: f.h,
		Offset:     off,
		Data:       data,
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return 0, fuse.ENOSYS
	}
	return uint32(resp.WriteSize), resp.Code
}

func (f *WsFsFile) Flock(flags int) fuse.Status {
	r := Request{
		Method:     MethodFileFlock,
		FileHandle: f.h,
		Flags:      uint32(flags),
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return fuse.ENOSYS
	}
	return resp.Code
}

func (f *WsFsFile) Flush() fuse.Status {
	return f.Fsync(0)
}

func (f *WsFsFile) Release() {
	r := Request{
		Method:     MethodFileRelease,
		FileHandle: f.h,
	}
	f.fs.getResponse(&r)
}

func (f *WsFsFile) GetAttr(attr *fuse.Attr) fuse.Status {
	r := Request{
		Method:     MethodFileGetAttr,
		FileHandle: f.h,
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return fuse.ENOSYS
	}
	if resp.Stat != nil {
		*attr = *resp.Stat
	}
	return resp.Code
}

func (f *WsFsFile) Fsync(flags int) (code fuse.Status) {
	r := Request{
		Method:     MethodFileFsync,
		FileHandle: f.h,
		Flags:      uint32(flags),
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return fuse.ENOSYS
	}
	return resp.Code
}

func (f *WsFsFile) Utimens(atime *time.Time, mtime *time.Time) fuse.Status {
	return fuse.ENOSYS
}

func (f *WsFsFile) Truncate(size uint64) fuse.Status {
	r := Request{
		Method:     MethodFileTruncate,
		FileHandle: f.h,
		Size:       uint32(size),
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return fuse.ENOSYS
	}
	return resp.Code
}

func (f *WsFsFile) Chown(uid uint32, gid uint32) fuse.Status {
	r := Request{
		Method:     MethodFileChown,
		FileHandle: f.h,
		UID:        uid,
		GID:        gid,
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return fuse.ENOSYS
	}
	return resp.Code
}

func (f *WsFsFile) Chmod(perms uint32) fuse.Status {
	r := Request{
		Method:     MethodFileChmod,
		FileHandle: f.h,
		Flags:      perms,
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return fuse.ENOSYS
	}
	return resp.Code
}

func (f *WsFsFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) {
	r := Request{
		Method:     MethodFileAllocate,
		FileHandle: f.h,
		Mode:       mode,
		Size:       uint32(size),
		Offset:     int64(off),
	}
	resp, ok := f.fs.getResponse(&r)
	if !ok {
		return fuse.ENOSYS
	}
	return resp.Code
}
