package kubelwagen

import (
	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/pathfs"
	"github.com/sirupsen/logrus"
)

type WsFs struct {
	pathfs.FileSystem
	req chan RequestCallback
}

type WsFsOpts struct {
	ReadOnly bool
	NonEmpty bool
}

func NewWsFs(opts WsFsOpts, req chan RequestCallback, closer chan bool) *pathfs.PathNodeFs {
	var fs pathfs.FileSystem
	wfs := &WsFs{
		FileSystem: pathfs.NewDefaultFileSystem(),
		req:        req,
	}

	// TODO(barakmich): spin up a goroutine to handle notify requests
	fs = wfs
	if opts.ReadOnly {
		fs = pathfs.NewReadonlyFileSystem(fs)
	}
	return pathfs.NewPathNodeFs(fs, nil)
}

func getChannel() chan Response {
	return make(chan Response)
}

func (fs *WsFs) String() string {
	return "kubelwagen"
}

func (fs *WsFs) getResponse(r *Request) (Response, bool) {
	c := getChannel()
	fs.req <- RequestCallback{
		message:  *r,
		response: c,
	}
	resp, ok := <-c
	return resp, ok
}

func (fs *WsFs) OpenDir(name string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
	r := Request{
		Method: MethodOpenDir,
		Path:   name,
	}
	resp, ok := fs.getResponse(&r)
	if !ok {
		logrus.Errorln("Response to request channel closed")
		return fs.FileSystem.OpenDir(name, context)
	}
	return resp.Dirents, resp.Code
}

func (fs *WsFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	r := Request{
		Method: MethodGetAttr,
		Path:   name,
	}
	resp, ok := fs.getResponse(&r)
	if !ok {
		logrus.Errorln("Response to request channel closed")
		return fs.FileSystem.GetAttr(name, context)
	}
	return resp.Stat, resp.Code
}

func (fs *WsFs) StatFs(name string) *fuse.StatfsOut {
	r := Request{
		Method: MethodStatFs,
		Path:   name,
	}
	resp, ok := fs.getResponse(&r)
	if !ok {
		logrus.Errorln("Response to request channel closed")
		return fs.FileSystem.StatFs(name)
	}
	return resp.Statfs

}
