package localserver

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/pion/webrtc/v3"
)

const (
	CREATE_FOLDER            = "create_folder"
	COPY_FOLDER              = "copy_folder"
	COPY_FILE                = "copy_file"
	CUT_FILE                 = "cut_file"
	CUT_FOLDER               = "cut_folder"
	RENAME_FOLDER            = "rename_folder"
	RENAME_FILE              = "rename_file"
	DELETE_FOLDER            = "delete_folder"
	DELETE_FILE              = "delete_file"
	UPDATE_PERMISSIONS       = "update_permissions"
	GET_FS_ENTITIES          = "get_fs_entities"
	ADD_FS_ENTITY_MEMBERS    = "add_fs_entity_members"
	REMOVE_FS_ENTITY_MEMBERS = "remove_fs_entity_members"
	ZONE_UPLOAD_FILE         = "zone_upload_file"
	ZONE_DOWNLOAD_FILE       = "zone_download_file"
)

const (
	CREATE_FOLDER_DONE            = "create_folder_done"
	CREATE_FILE_DONE              = "create_file_done"
	COPY_FOLDER_DONE              = "copy_folder_done"
	COPY_FILE_DONE                = "copy_file_done"
	CUT_FILE_DONE                 = "cut_file_done"
	CUT_FOLDER_DONE               = "cut_folder_done"
	RENAME_FOLDER_DONE            = "rename_folder_done"
	RENAME_FILE_DONE              = "rename_file_done"
	DELETE_FOLDER_DONE            = "delete_folder_done"
	DELETE_FILE_DONE              = "delete_file_done"
	UPDATE_PERMISSIONS_DONE       = "update_permissions_done"
	GET_FS_ENTITIES_DONE          = "get_fs_entities_done"
	ADD_FS_ENTITY_MEMBERS_DONE    = "add_fs_entity_members_done"
	REMOVE_FS_ENTITY_MEMBERS_DONE = "remove_fs_entity_members_done"
	ZONE_DOWNLOAD_FILE_DONE       = "zone_download_file_done"
	ZONE_UPLOAD_FILE_DONE         = "zone_upload_file_done"
)

const (
	PARENT = "parent"
)

// ZoneFileHandler : Handle all interaction of the node zone related to the file system
type ZoneFileHandler[T ZippytalFSInstance] struct {
	ZoneId               string
	HostId               string
	ZoneMembersId        []string
	DataChannels         map[string]*DataChannel
	FileDataChannels     map[string]*DataChannel
	FileDataChannelsFlag *uint32
	Flag                 *uint32
	FSInstanceFlag       *uint32
	Publishers           []<-chan *ZoneRequest
	FSInstance           T
	reqChans             []chan<- *ZoneRequest
	DB                   *ZoneFilesDBHandler
}

// FSEntityAccessRights : representation of the different rights users can have on a ZoneFSEntity
type FSEntityAccessRights struct {
	// Read : this field for folder determine if the member is allowed to see this folder only because he is allowed to read a child folder or because he actually is authorized to read this folder (hard to explain)
	Read bool `json:"read"`
	// Write : this field for folder determine if the user can upload file in this folder and for file if the user can edit the file (future feature).
	Write bool `json:"write"`
	// Download : this field for folder determine if the user can download a zip of the folder (future feature) and for file if he can download the file.
	Download bool `json:"download"`
	// Rename : determine the ability of the user to change the name of the fsEntity
	Rename bool `json:"rename"`
}

// ZoneFSEntity : representation of a FSEntity (file or folder) for the zone fs feature
type ZoneFSEntity struct {
	Name         string                           `json:"name"`
	Owner        string                           `json:"owner"`
	Type         string                           `json:"type"`
	Folder       bool                             `json:"folder"`
	ModTime      string                           `json:"modTime"`
	CreationTime string                           `json:"creationTime"`
	Size         uint64                           `json:"size"`
	Members      map[string]*FSEntityAccessRights `json:"members"`
}

// NewZoneFileHandler: factory function to create a zone file handler the name of the parameters are explicit, this is the only way to safely create a ZoneFSEntity
func NewZoneFileHandler(_ string, zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneFileHandler *ZoneFileHandler[*FSInstance], err error) {
	db, err := NewZoneFilesDBHandler(zoneId)
	if err != nil {
		return
	}
	initFsDirectory := func(u string) (err error) {
		logger.Printf("creating fs directory for user %s...\n", u)
		baseConfig := ZoneFSEntity{
			Name:   u,
			Owner:  u,
			Type:   "private",
			Folder: true,
			Members: map[string]*FSEntityAccessRights{
				u: {
					Read:     true,
					Write:    true,
					Download: true,
					Rename:   true,
				},
			},
		}
		err = db.AddNewFSEntity("", &baseConfig)
		return
	}
	if _, dirErr := os.ReadDir(filepath.Join(dataPath, "data", "zones", zoneId, "fs")); os.IsNotExist(dirErr) {
		dirErr := os.MkdirAll(filepath.Join(dataPath, "data", "zones", zoneId, "fs"), 0700)
		if dirErr != nil {
			return
		}
	}
	for _, user := range authorizedMembers {
		if _, dirErr := os.ReadDir(filepath.Join(dataPath, "data", "zones", zoneId, "fs", user)); os.IsNotExist(dirErr) {
			if e := initFsDirectory(user); e != nil {
				logger.Println(e)
			}
		}
	}
	fSInstanceFlag := uint32(0)
	fSDCFlag := uint32(0)
	fsInstance := NewFSInstance(zoneId, owner, authorizedMembers)
	zoneFileHandler = &ZoneFileHandler[*FSInstance]{
		ZoneId:               zoneId,
		ZoneMembersId:        authorizedMembers,
		DataChannels:         dataChannels,
		FileDataChannels:     make(map[string]*DataChannel),
		FileDataChannelsFlag: &fSDCFlag,
		FSInstanceFlag:       &fSInstanceFlag,
		FSInstance:           fsInstance,
		DB:                   db,
		Flag:                 flag,
	}
	return
}

// func (zfh *ZoneFileHandler) sendZoneRequest(reqType string, from string, payload map[string]interface{}) {
// 	go func() {
// 		for _, rc := range zfh.reqChans {
// 			rc <- &ZoneRequest{
// 				ReqType: reqType,
// 				From:    from,
// 				Payload: payload,
// 			}
// 		}
// 	}()
// }

func (zfh *ZoneFileHandler[T]) Init(ctx context.Context, authorizedMembers []string) (err error) {
	for _, member := range authorizedMembers {
		if serr := zfh.SetPublicRootFolders(member); serr != nil {
			logger.Println(serr)
		}
	}
	return
}

func (zfh *ZoneFileHandler[T]) sendDataChannelMessage(reqType string, from string, to string, payload map[string]interface{}) (<-chan struct{}, <-chan error) {
	done, errCh := make(chan struct{}), make(chan error)
	go func() {
		if err := atomicallyExecute(zfh.FileDataChannelsFlag, func() (err error) {
			if _, ok := zfh.FileDataChannels[to]; ok {
				bs, jsonErr := json.Marshal(&ZoneResponse{
					Type:    reqType,
					From:    from,
					To:      to,
					Payload: payload,
				})
				if jsonErr != nil {
					return jsonErr
				}
				<-time.After(20 * time.Millisecond)
				err = zfh.FileDataChannels[to].DataChannel.SendText(string(bs))
			}
			return
		}); err != nil {
			errCh <- err
			return
		}
		done <- struct{}{}
	}()
	return done, errCh
}

func (zfh *ZoneFileHandler[T]) sendZoneRequest(reqType string, from string, payload map[string]interface{}) {
	go func() {
		for _, rc := range zfh.reqChans {
			rc <- &ZoneRequest{
				ReqType: reqType,
				From:    from,
				Payload: payload,
			}
		}
	}()
}

func (zfh *ZoneFileHandler[T]) Subscribe(ctx context.Context, publisher <-chan *ZoneRequest) (reqChan chan *ZoneRequest, done chan struct{}, errCh chan error) {
	reqChan, done, errCh = make(chan *ZoneRequest), make(chan struct{}), make(chan error)
	zfh.reqChans = append(zfh.reqChans, reqChan)
	go func() {
		for {
			select {
			case <-ctx.Done():
				done <- struct{}{}
				return
			case req := <-publisher:
				if err := zfh.handleZoneRequest(ctx, req); err != nil {
					errCh <- err
				}
			}
		}
	}()
	return
}

// func (zfh *ZoneFileHandler[T]) signalCandidate(from string, to string, candidate *webrtc.ICECandidate) (err error) {
// 	d, e := zfh.sendDataChannelMessage(string(ZONE_FS_WEBRTC_CANDIDATE), from, to, map[string]interface{}{
// 		"from":          from,
// 		"to":            to,
// 		"candidate":     candidate.ToJSON().Candidate,
// 		"sdpMid":        *candidate.ToJSON().SDPMid,
// 		"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// 	})
// 	select {
// 	case <-d:
// 	case err = <-e:
// 	}
// 	return
// }

// GetFSEntities: Return a list of ZoneFSEntity to the user with the provided userId
func (zfh *ZoneFileHandler[T]) GetFSEntities(userId string, section string, basePath string, limit int, lastIndex int, backward bool) (err error) {
	var fsEntities []*ZoneFSEntity
	var currentPath string = basePath
	var listFSEntities func(string, string, int, int, bool)
	listFSEntities = func(userId, path string, limit, lastIndex int, backward bool) {
		fsEntities, _, err = zfh.DB.ListZoneFSEntity(path, userId, lastIndex, limit)
		if err != nil {
			return
		}
		currentPath = path
		if len(fsEntities) == 1 {
			if rights, ok := fsEntities[0].Members[userId]; ok {
				if !rights.Read {
					if !backward {
						listFSEntities(userId, filepath.Join(path, fsEntities[0].Name), 100, 0, backward)
					} else {
						splittedPath := filepath.SplitList(path)
						if len(splittedPath) > 1 {
							listFSEntities(userId, filepath.Dir(path), 100, 0, backward)
						} else {
							listFSEntities(userId, "", 100, 0, backward)
						}
					}
				}
			}
		}
	}
	listFSEntities(userId, basePath, 100, 0, backward)
	var parent *ZoneFSEntity
	if len(filepath.SplitList(basePath)) > 0 {
		parent, err = zfh.DB.GetFSEntity(filepath.Dir(basePath), filepath.Base(basePath))
		if err != nil {
			return
		}
		logger.Println("------------------ parent is --------------")
		logger.Println(parent)
	}
	done, errCh := zfh.sendDataChannelMessage(GET_FS_ENTITIES, "node", userId, map[string]interface{}{
		"fsEntities":  fsEntities,
		"parent":      parent,
		"currentPath": currentPath,
		"section":     section,
	})
	select {
	case <-done:
		fmt.Println("done fs entity get")
	case err = <-errCh:
	}
	return
}

// CreateFolder: create a ZoneFSEntity folder mapped to a real folder on the disk
func (zfh *ZoneFileHandler[T]) CreateFolder(path string, config *ZoneFSEntity) (err error) {
	if config.Type == PARENT {
		parentPath := filepath.Dir(path)
		parentFolderName := filepath.Base(path)
		logger.Println(parentPath, "-------", parentFolderName)
		var folder *ZoneFSEntity
		if len(parentPath) > 1 {
			folder, err = zfh.DB.GetFSEntity(parentPath, parentFolderName)
		} else {
			folder, err = zfh.DB.GetFSEntity("", parentFolderName)
		}
		if err != nil {
			return
		}
		config.Members = make(map[string]*FSEntityAccessRights)
		for k, v := range folder.Members {
			config.Members[k] = &FSEntityAccessRights{
				Read:     v.Read,
				Write:    v.Write,
				Download: v.Download,
				Rename:   v.Rename,
			}
		}
	}
	if err = zfh.DB.AddNewFSEntity(path, config); err != nil {
		return
	}
	for member := range config.Members {
		done, errCh := zfh.sendDataChannelMessage(CREATE_FOLDER_DONE, "node", member, map[string]interface{}{
			"path":     path,
			"fsEntity": config,
		})
		select {
		case <-done:
		case err = <-errCh:
			logger.Println(err)
		}
	}
	return
}

// CreateFile: create a ZoneFSEntity file mapped to a real file on the disk
func (zfh *ZoneFileHandler[T]) CreateFile(path, fileName string, config *ZoneFSEntity) (err error) {
	splittedPath := strings.Split(path, "/")
	if config.Type == PARENT {
		logger.Println(strings.Join(splittedPath[:len(splittedPath)-1], "/"), "-------", splittedPath[len(splittedPath)-1])
		var folder *ZoneFSEntity
		if len(splittedPath) > 1 {
			folder, err = zfh.DB.GetFSEntity(strings.Join(splittedPath[:len(splittedPath)-1], "/"), splittedPath[len(splittedPath)-1])
		} else {
			folder, err = zfh.DB.GetFSEntity("", splittedPath[0])
		}
		if err != nil {
			return
		}
		config.Members = make(map[string]*FSEntityAccessRights)
		for k, v := range folder.Members {
			config.Members[k] = &FSEntityAccessRights{
				Read:     v.Read,
				Write:    v.Write,
				Download: v.Download,
				Rename:   v.Rename,
			}
		}
	}
	if err = zfh.DB.AddNewFSEntity(path, config); err != nil {
		return
	}
	for member := range config.Members {
		done, errCh := zfh.sendDataChannelMessage(CREATE_FILE_DONE, "node", member, map[string]interface{}{
			"path":     path,
			"fsEntity": config,
		})
		select {
		case <-done:
		case err = <-errCh:
			logger.Println(err)
		}
	}
	return
}

// EditFolderType: change the type of the folder and modify rights of the users according to the new ZoneFSEntity type provided
func (zfh *ZoneFileHandler[T]) EditFolderType(userId string, path string, folderName string, newFolderType string) (err error) {
	folder, err := zfh.DB.GetFSEntity(path, folderName)
	if err != nil {
		return
	}
	folder.Type = newFolderType
	if err = zfh.DB.SetFSEntity(path, folderName, folder); err != nil {
		return
	}
	done, errCh := zfh.sendDataChannelMessage("", "node", userId, map[string]interface{}{
		"newFolder": folder,
	})
	select {
	case <-done:
	case err = <-errCh:
	}
	return
}

func (zfh *ZoneFileHandler[T]) EditFileType(path string, fileName string, newFileType string) (err error) {
	return
}

// AddFolderMember: add a list of members to the map of users allowed to access the folder with the provided folderName and set the rights
func (zfh *ZoneFileHandler[T]) AddFolderMember(userId string, path string, folderName string, members []interface{}, read bool, write bool, download bool, rename bool) (err error) {
	var addMembersDb func(string, string, bool, bool, bool, bool, bool) (folder *ZoneFSEntity, err error)
	addMembersDb = func(path string, folderName string, read bool, write bool, download bool, rename bool, init bool) (folder *ZoneFSEntity, err error) {
		folder, err = zfh.DB.GetFSEntity(path, folderName)
		if err != nil {
			return
		}
		childrens := make([]*ZoneFSEntity, 0)
		if init {
			childrens, _, err = zfh.DB.ListZoneFSEntity(filepath.Join(path, folderName), userId, 0, 100)
			if err != nil {
				logger.Println("cannot get siblings folders:", err)
				return
			}
		}
		for _, newMember := range members {
			if m, ok := newMember.(string); ok {
				if _, ok := folder.Members[m]; !ok {
					folder.Members[m] = &FSEntityAccessRights{
						Read:     read,
						Write:    write,
						Download: download,
						Rename:   rename,
					}
				}
				if init {
					go func() {
						for _, children := range childrens {
							logger.Println("------:", filepath.Join(path, folderName), "-", children.Name)
							if children.Type != "private" {
								if _, err = addMembersDb(filepath.Join(path, folderName), children.Name, read, write, download, rename, true); err != nil {
									logger.Println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*")
									logger.Println("error from ttttthheeere:", err)
									logger.Println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*")
								}
							}
						}
					}()
				}
			}
		}
		err = zfh.DB.SetFSEntity(path, folderName, folder)
		return
	}
	folder, err := addMembersDb(path, folderName, read, write, download, rename, true)
	if err != nil {
		return
	}
	splittedPath := strings.Split(path, "/")
	for i := 1; i <= len(splittedPath); i++ {
		logger.Println(i)
		var addErr error
		if i == len(splittedPath) {
			_, addErr = addMembersDb("", splittedPath[0], false, false, false, false, false)

		} else {
			_, addErr = addMembersDb(strings.Join(splittedPath[:len(splittedPath)-i], "/"), splittedPath[len(splittedPath)-i], false, false, false, false, false)

		}
		if addErr != nil {
			logger.Println(addErr)
			break
		}
	}
	for member := range folder.Members {
		done, errCh := zfh.sendDataChannelMessage(ADD_FS_ENTITY_MEMBERS_DONE, "node", member, map[string]interface{}{
			"path": path,
		})
		select {
		case <-done:
		case sendErr := <-errCh:
			logger.Println(sendErr)
		}
	}
	for _,member := range members {
		go func(m string) {
			bs, err := json.Marshal(map[string]any{
				"zoneId":     zfh.ZoneId,
				"folderName": folderName,
				"folderPath": path,
				"zoneHost":   NodeID,
			})
			if err != nil {
				return
			}
			zfh.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
				"type":       "added_in_folder",
				"title":      "New folder shared 📁",
				"body":       fmt.Sprintf("%s granted you access to the folder %s", userId, folderName),
				"isPushed":   true,
				"payload":    string(bs),
				"recipients": []string{m},
			})
		}(member.(string))
	}
	return
}

func (zfh *ZoneFileHandler[T]) AddFileMember(path string, filename string, members []interface{}, read bool, write bool, download bool, rename bool) (err error) {
	return
}

func (zfh *ZoneFileHandler[T]) RemoveFolderMember(userId string, path string, folderName string, members []interface{}) (err error) {
	membersM := make(map[string]bool)
	staticMembersM := make(map[string]bool)
	for _, member := range members {
		if m, ok := member.(string); ok {
			membersM[m] = true
			staticMembersM[m] = true
		}
	}
	var removeChildMemberDb func(string, string) (folder *ZoneFSEntity, err error)
	removeChildMemberDb = func(path, folderName string) (folder *ZoneFSEntity, err error) {
		childrens, _, err := zfh.DB.ListZoneFSEntity(filepath.Join(path, folderName), userId, 0, 100)
		if err != nil {
			logger.Println("cannot get siblings folders:", err)
			return
		}
		go func() {
			for _, children := range childrens {
				for member := range staticMembersM {
					if _, ok := children.Members[member]; ok && member != children.Owner {
						delete(children.Members, member)
					}
				}
				logger.Println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*")
				logger.Println(filepath.Join(path, folderName), ":", children.Name)
				logger.Println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*")
				_, _ = removeChildMemberDb(filepath.Join(path, folderName), children.Name)
				err = zfh.DB.SetFSEntity(filepath.Join(path, folderName), children.Name, children)
			}
		}()
		return
	}
	removeMemberDb := func(path, folderName string, init bool) (folder *ZoneFSEntity, err error) {
		folder, err = zfh.DB.GetFSEntity(path, folderName)
		if err != nil {
			return
		}
		siblings, _, err := zfh.DB.ListZoneFSEntity(path, userId, 0, 100)
		if err != nil {
			logger.Println("cannot get siblings folders:", err)
			return
		}
		if init {
			_, _ = removeChildMemberDb(path, folderName)
		}
		for member := range membersM {
			if _, ok := folder.Members[member]; ok && member != folder.Owner {
				if !folder.Members[member].Read || init {
					delete(folder.Members, member)
				} else {
					delete(membersM, member)
				}
				for _, sibling := range siblings {
					if sibling.Name != folder.Name {
						if _, ok := sibling.Members[member]; ok {
							delete(membersM, member)
						}
					}
				}
			}
		}
		err = zfh.DB.SetFSEntity(path, folderName, folder)
		return
	}
	folder, err := removeMemberDb(path, folderName, true)
	if err != nil {
		return
	}
	splittedPath := strings.Split(path, "/")
	for i := 1; i <= len(splittedPath) && len(membersM) > 0; i++ {
		logger.Println(i)
		var addErr error
		if i == len(splittedPath) {
			_, addErr = removeMemberDb("", splittedPath[0], false)

		} else {
			_, addErr = removeMemberDb(strings.Join(splittedPath[:len(splittedPath)-i], "/"), splittedPath[len(splittedPath)-i], false)

		}
		if addErr != nil {
			logger.Println(addErr)
			break
		}
	}
	for member := range folder.Members {
		done, errCh := zfh.sendDataChannelMessage(REMOVE_FS_ENTITY_MEMBERS_DONE, "node", member, map[string]interface{}{
			"path": filepath.Join(path, folderName),
		})
		select {
		case <-done:
		case sendErr := <-errCh:
			logger.Println(sendErr)
		}
	}
	for _, member := range members {
		if _, ok := member.(string); ok {
			go func(m string) {
				fmt.Println("sending unshare notification",m)
				bs, err := json.Marshal(map[string]any{
					"zoneId":     zfh.ZoneId,
					"folderName": folderName,
					"zoneHost":   NodeID,
				})
				if err != nil {
					fmt.Println("error there",err)
					return
				}
				zfh.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
					"type":       "removed_from_folder",
					"title":      "Folder unshared ⛔️",
					"body":       fmt.Sprintf("%s stopped your access to the folder %s", userId, folderName),
					"isPushed":   true,
					"payload":    string(bs),
					"recipients": []string{m},
				})
			}(member.(string))
			done, errCh := zfh.sendDataChannelMessage(REMOVE_FS_ENTITY_MEMBERS_DONE, "node", member.(string), map[string]interface{}{
				"path": filepath.Join(path, folderName),
			})
			select {
			case <-done:
			case sendErr := <-errCh:
				logger.Println(sendErr)
			}
		}
	}
	return
}

func (zfh *ZoneFileHandler[T]) RemoveFileMember(path, filename, members, read, write, download, rename bool) (err error) {
	return
}

func (zfh *ZoneFileHandler[T]) ClearUserFolders(userId string) (err error) {
	fsEntities,_,err := zfh.DB.ListZoneFSEntity("",userId,0,100)
	if err != nil {
		return
	}
	for _, fsEntity := range fsEntities {
		go func(f *ZoneFSEntity) {
			if e := zfh.RemoveFolderMember(f.Owner,"",f.Name,[]any{userId}); e != nil {
			logger.Println(e)
		}
		}(fsEntity)
	}
	return
}

func (zfh *ZoneFileHandler[T]) RenameFolder(path, currentName, newName string) (err error) {
	fsEntity, err := zfh.DB.GetFSEntity(path, currentName)
	if err != nil {
		return
	}
	fsEntity.Name = newName
	if err = os.Rename(filepath.Join(filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs"), path, currentName), filepath.Join(filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs"), path, newName)); err != nil {
		return
	}
	if err = zfh.DB.SetFSEntity(path, currentName, fsEntity); err != nil {
		return
	}
	for member := range fsEntity.Members {
		done, errCh := zfh.sendDataChannelMessage(RENAME_FOLDER_DONE, "node", member, map[string]interface{}{
			"path":     filepath.Join(path, newName),
			"folderId": newName,
		})
		select {
		case <-done:
		case sendErr := <-errCh:
			logger.Println(sendErr)
		}
	}
	return
}

func (zfh *ZoneFileHandler[T]) RenameFile(path, currentName, newName string) (err error) {
	fsEntity, err := zfh.DB.GetFSEntity(path, currentName)
	if err != nil {
		return
	}
	fsEntity.Name = newName
	if err = os.Rename(filepath.Join(filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs"), path, "__files__", currentName), filepath.Join(filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs"), path, "__files__", newName)); err != nil {
		return
	}
	if err = zfh.DB.SetFSEntity(path, currentName, fsEntity); err != nil {
		return
	}
	for member := range fsEntity.Members {
		done, errCh := zfh.sendDataChannelMessage(RENAME_FILE_DONE, "node", member, map[string]interface{}{
			"path":     filepath.Join(path, newName),
			"folderId": newName,
		})
		select {
		case <-done:
		case sendErr := <-errCh:
			logger.Println(sendErr)
		}
	}
	return
}

func (zfh *ZoneFileHandler[T]) UpdatePermissions(path, name, userId string, newPermission *FSEntityAccessRights) (err error) {
	var updatePermission func(string, string) error
	updatePermission = func(path, name string) (err error) {
		fsEntity, err := zfh.DB.GetFSEntity(path, name)
		if err != nil {
			return
		}
		if fsEntity.Folder {
			splittedPath := append(filepath.SplitList(path), name)
			childrens, _, err := zfh.DB.ListZoneFSEntity(filepath.Join(splittedPath...), userId, 0, 100)
			if err != nil {
				return err
			}
			go func() {
				for _, children := range childrens {
					if children.Type == PARENT {
						if err = updatePermission(filepath.Join(splittedPath...), children.Name); err != nil {
							return
						}
					}
				}
			}()
		}
		fsEntity.Members[userId] = newPermission
		if err = zfh.DB.SetFSEntity(path, name, fsEntity); err != nil {
			return
		}
		for member := range fsEntity.Members {
			done, errCh := zfh.sendDataChannelMessage(UPDATE_PERMISSIONS_DONE, "node", member, map[string]interface{}{
				"path": filepath.Join(path, name),
			})
			select {
			case <-done:
			case sendErr := <-errCh:
				logger.Println(sendErr)
			}
		}
		return
	}
	err = updatePermission(path, name)
	return
}

func (zfh *ZoneFileHandler[T]) DeleteFolder(path, name string) (err error) {
	fsEntity, err := zfh.DB.GetFSEntity(path, name)
	if err != nil {
		return
	}
	if err = zfh.DB.DeleteFolder(path, name); err != nil {
		return
	}
	for member := range fsEntity.Members {
		done, errCh := zfh.sendDataChannelMessage(DELETE_FOLDER_DONE, "node", member, map[string]interface{}{
			"path":     filepath.Join(path, name),
			"folderId": name,
		})
		select {
		case <-done:
		case sendErr := <-errCh:
			logger.Println(sendErr)
		}
	}
	return
}

func (zfh *ZoneFileHandler[T]) DeleteFile(path, name string) (err error) {
	fsEntity, err := zfh.DB.GetFSEntity(path, name)
	if err != nil {
		return
	}
	if err = zfh.DB.DeleteFile(path, name); err != nil {
		return
	}
	for member := range fsEntity.Members {
		done, errCh := zfh.sendDataChannelMessage(DELETE_FOLDER_DONE, "node", member, map[string]interface{}{
			"path":     filepath.Join(path, name),
			"folderId": name,
		})
		select {
		case <-done:
		case sendErr := <-errCh:
			logger.Println(sendErr)
		}
	}
	return
}

func (zfh *ZoneFileHandler[T]) CopyFile(src, dst string, init bool, fsEntity *ZoneFSEntity) (err error) {
	var srcfd *os.File
	var dstfd *os.File
	var srcinfo os.FileInfo
	var srcPath string
	var dstPath string
	if init {
		srcPath = filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs", filepath.Dir(src), "__files__", filepath.Base(src))
		dstPath = filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs", filepath.Dir(dst), "__files__", filepath.Base(dst))
	} else {
		srcPath = filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs", src)
		dstPath = filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs", dst)
	}
	if err = os.MkdirAll(filepath.Dir(dstPath), 0700); err != nil && !os.IsExist(err) {
		return
	}
	if srcfd, err = os.Open(srcPath); err != nil {
		return
	}
	defer srcfd.Close()
	if dstfd, err = os.Create(dstPath); err != nil {
		return
	}
	defer dstfd.Close()
	if _, err = io.Copy(dstfd, srcfd); err != nil {
		return
	}
	if srcinfo, err = os.Stat(srcPath); err != nil {
		return
	}
	if err = os.Chmod(dstPath, srcinfo.Mode()); err != nil {
		return
	}
	if init {
		err = zfh.DB.AddNewFSEntity(filepath.Dir(dst), fsEntity)
		for member := range fsEntity.Members {
			done, errCh := zfh.sendDataChannelMessage(COPY_FILE_DONE, "node", member, map[string]interface{}{
				"path": dst,
			})
			select {
			case <-done:
			case sendErr := <-errCh:
				logger.Println(sendErr)
			}
		}
	}
	return
}

func (zfh *ZoneFileHandler[T]) CopyDir(src, dst string, init bool, fsEntity *ZoneFSEntity) (err error) {
	var fds []os.FileInfo
	var srcinfo os.FileInfo
	srcPath := filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs", src)
	dstPath := filepath.Join(dataPath, "data", "zones", zfh.ZoneId, "fs", dst)
	if srcinfo, err = os.Stat(srcPath); err != nil {
		return
	}
	if init {
		logger.Println("---------------------adding new fs entity---------------------")
		if err = zfh.DB.AddNewFSEntity(filepath.Dir(dst), fsEntity); err != nil {
			return
		}
	} else {
		if err = os.MkdirAll(dstPath, srcinfo.Mode()); err != nil {
			return
		}
	}
	if fds, err = ioutil.ReadDir(srcPath); err != nil {
		return
	}
	for _, fd := range fds {
		srcfp := path.Join(src, fd.Name())
		dstfp := path.Join(dst, fd.Name())
		if fd.IsDir() {
			if err = zfh.CopyDir(srcfp, dstfp, false, nil); err != nil {
				logger.Println(err)
			}
		} else {
			if err = zfh.CopyFile(srcfp, dstfp, false, nil); err != nil {
				logger.Println(err)
			}
		}
	}
	if fsEntity != nil {
		for member := range fsEntity.Members {
			done, errCh := zfh.sendDataChannelMessage(COPY_FOLDER_DONE, "node", member, map[string]interface{}{
				"path": dst,
			})
			select {
			case <-done:
			case sendErr := <-errCh:
				logger.Println(sendErr)
			}
		}
	}
	return
}

func (zfh *ZoneFileHandler[T]) CutFolder(id, path, dstPath string, init bool, fsEntity *ZoneFSEntity) (err error) {
	if err = zfh.CopyDir(path, dstPath, init, fsEntity); err != nil {
		return
	}
	err = zfh.DeleteFolder(filepath.Dir(path), filepath.Base(path))
	return
}

func (zfh *ZoneFileHandler[T]) CutFile(id, path, dstPath string, init bool, fsEntity *ZoneFSEntity) (err error) {
	if err = zfh.CopyFile(path, dstPath, init, fsEntity); err != nil {
		return
	}
	err = zfh.DeleteFile(filepath.Dir(path), filepath.Base(path))
	return
}

// func (zfh *ZoneFileHandler[T]) ConnectToFSInstance(channelId string, userId string, sdp string) (err error) {
// 	err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) {
// 		d, e := zfh.FSInstance.HandleOffer(context.Background(), channelId, userId, sdp, zfh.HostId, zfh.sendDataChannelMessage, zfh.signalCandidate)
// 		select {
// 		case <-d:
// 		case err = <-e:
// 		}
// 		return
// 	})
// 	return
// }

// func (zfh *ZoneFileHandler[T]) LeaveFSInstance(
// 	userId string) (err error) {
// 	err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) {
// 		zfh.FSInstance.HandleLeavingMember(userId)
// 		return
// 	})
// 	return
// }

func (zfh *ZoneFileHandler[T]) SetPublicRootFolders(user string) (err error) {
	return
}

func (zfh *ZoneFileHandler[T]) fileUpload(chatId string, filename string, userId string, dc *DataChannel) {
	var writePipe chan<- []byte
	var done bool
	uploadDone := func() {
		if writePipe != nil {
			close(writePipe)
			writePipe = nil
		}
		done = true
	}
	dc.DataChannel.OnError(func(err error) {
		logger.Println(err)
		logger.Println("abort...")
		if !done {
			uploadDone()
		}
		if fufErr := zfh.FSInstance.FileUploadFailed(chatId, filename, userId); fufErr != nil {
			logger.Println(fufErr)
		}
	})
	dc.DataChannel.OnClose(func() {
		if done {
			logger.Println("closing gracefully...")
		} else {
			logger.Println("abort...")
			uploadDone()
			if fufErr := zfh.FSInstance.FileUploadFailed(chatId, filename, userId); fufErr != nil {
				logger.Println(fufErr)
			}
		}
	})
	dc.DataChannel.OnMessage(func(msg webrtc.DataChannelMessage) {
		if msg.IsString {
			if string(msg.Data) == "init_upload" {
				logger.Println("init upload....")
				var initErr error
				if writePipe, initErr = zfh.FSInstance.SetupFileUpload(chatId, filename, userId, dc.DataChannel); initErr != nil {
					_ = dc.DataChannel.SendText("abort")
					_ = dc.DataChannel.Close()
					return
				}
				logger.Println("upload ready !")
				_ = dc.DataChannel.SendText("upload_ready")
			} else if string(msg.Data) == "upload_done" {
				uploadDone()
			}
		} else {
			writePipe <- msg.Data
		}
	})
	dc.DataChannel.OnOpen(func() {
		_ = dc.DataChannel.SendText("channel_ready")
	})
}

func (zfh *ZoneFileHandler[T]) fileDownload(chatId string, filename string, userId string, dc *DataChannel) {
	var done bool
	dc.DataChannel.OnError(func(err error) {
		if !done {
			logger.Println("abort...")
			if fdf := zfh.FSInstance.FileDownloadFailed(chatId, filename, userId); fdf != nil {
				logger.Println(fdf)
			}
		}
	})
	dc.DataChannel.OnClose(func() {
		if !done {
			logger.Println("abort...")
			if fdf := zfh.FSInstance.FileDownloadFailed(chatId, filename, userId); fdf != nil {
				logger.Println(fdf)
			}
		}
	})
	dc.DataChannel.OnMessage(func(msg webrtc.DataChannelMessage) {
		if msg.IsString {
			if string(msg.Data) == "init_download" {
				logger.Println("init download....")
				var initErr error
				if initErr = zfh.FSInstance.SetupFileDownload(chatId, filename, userId, dc.DataChannel); initErr != nil {
					_ = dc.DataChannel.SendText("abort")
					_ = dc.DataChannel.Close()
					return
				}
				logger.Println("download started !")
			} else if string(msg.Data) == "download_done" {
				done = true
			}
		}
	})
	dc.DataChannel.OnOpen(func() {
		_ = dc.DataChannel.SendText("channel_ready")
	})
}

func (zfh *ZoneFileHandler[T]) handleDataChannel(ctx context.Context, dc *DataChannel) (catched bool) {
	var label string
	_ = atomicallyExecute(dc.l, func() (err error) {
		label = dc.DataChannel.Label()
		return
	})
	if strings.Contains(label, "file_upload") {
		command := strings.Split(label, "|")
		if len(command) == 4 {
			catched = true
			go zfh.fileUpload(command[1], command[2], command[3], dc)
		}
		logger.Println(command)
	} else if strings.Contains(label, "file_download") {
		command := strings.Split(label, "|")
		catched = true
		go zfh.fileDownload(command[1], command[2], command[3], dc)
		logger.Println(command)
	} else if strings.Contains(label, "file_data") {
		command := strings.Split(label, "|")
		catched = true
		_ = atomicallyExecute(zfh.FileDataChannelsFlag, func() (err error) {
			zfh.FileDataChannels[command[1]] = dc
			return
		})
		dc.DataChannel.OnClose(func() {
			fmt.Println("closing gratefully fs dc...")
			_ = atomicallyExecute(zfh.FileDataChannelsFlag, func() (err error) {
				delete(zfh.FileDataChannels, command[1])
				return
			})
		})
		dc.DataChannel.OnError(func(err error) {
			fmt.Println("error in  fs dc...")
			_ = atomicallyExecute(zfh.FileDataChannelsFlag, func() (err error) {
				delete(zfh.FileDataChannels, command[1])
				return
			})
		})
	}
	return
}

func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneRequest) (err error) {
	switch req.ReqType {
	case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
		if err = verifyFieldsString(req.Payload, "userId"); err != nil {
			return
		}
		var index int
		var found bool
		for i, m := range zfh.ZoneMembersId {
			if m == req.Payload["userId"].(string) {
				index = i
				break
			}
		}
		if !found {
			err = fmt.Errorf("no such user in zone")
			return
		}
		zfh.ZoneMembersId = append(zfh.ZoneMembersId[:index], zfh.ZoneMembersId[index+1:]...)
		err = zfh.DeleteFolder("", req.Payload["userId"].(string))
	case string(NEW_AUTHORIZED_ZONE_MEMBER):
		if err = verifyFieldsString(req.Payload, "userId"); err != nil {
			return
		}
		var contain bool
		for _, m := range zfh.ZoneMembersId {
			if m == req.Payload["userId"].(string) {
				contain = true
				break
			}
		}
		if !contain {
			zfh.ZoneMembersId = append(zfh.ZoneMembersId, req.Payload["userId"].(string))
		}
		err = zfh.DB.AddNewFSEntity("", &ZoneFSEntity{
			Name:         req.Payload["userId"].(string),
			Owner:        req.Payload["userId"].(string),
			Type:         PRIVATE,
			Folder:       true,
			ModTime:      time.Now().Format(time.UnixDate),
			CreationTime: time.Now().Format(time.UnixDate),
			Size:         0,
			Members: map[string]*FSEntityAccessRights{
				req.Payload["userId"].(string): {
					Read:     true,
					Write:    true,
					Download: true,
					Rename:   true,
				},
			},
		})
	case LEAVE_ZONE:
		logger.Println("*-----------------handling leaving zone---------------*")
		if err = verifyFieldsString(req.Payload, "userId"); err != nil {
			return
		}
		//err = zfh.LeaveFSInstance(req.Payload["userId"].(string))
	case ZONE_UPLOAD_FILE_DONE:
		if err = verifyFieldsBool(req.Payload, "failed"); err != nil {
			return
		}
		if err = verifyFieldsString(req.Payload, "path", "userId", "fileName", "type"); err != nil {
			return
		}
		if err = verifyFieldsFloat64(req.Payload, "size"); err != nil {
			return
		}
		if req.Payload["failed"].(bool) {
			logger.Println(zfh.FSInstance.FileUploadFailed(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string)))
		} else {
			defer func() {
				//logger.Println(zfh.FSInstance.FileUploadDone(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string)))
			}()
			err = zfh.CreateFile(req.Payload["path"].(string), req.Payload["fileName"].(string), &ZoneFSEntity{
				Name:         req.Payload["fileName"].(string),
				Owner:        req.Payload["userId"].(string),
				Type:         req.Payload["type"].(string),
				Size:         uint64(req.Payload["size"].(float64)),
				ModTime:      time.Now().Format(time.UnixDate),
				CreationTime: time.Now().Format(time.UnixDate),
				Folder:       false,
				Members: map[string]*FSEntityAccessRights{
					req.Payload["userId"].(string): {
						Read:     true,
						Write:    true,
						Download: true,
						Rename:   true,
					},
				},
			})
		}
	// case ZONE_UPLOAD_FILE:
	// 	if err = verifyFieldsString(req.Payload, "path", "userId", "fileName"); err != nil {
	// 		return
	// 	}
	// 	err = zfh.FSInstance.SetupFileUpload(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string))
	// case ZONE_DOWNLOAD_FILE:
	// 	if err = verifyFieldsString(req.Payload, "path", "userId", "fileName"); err != nil {
	// 		return
	// 	}
	// 	err = zfh.FSInstance.SetupFileDownload(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string))
	case GET_FS_ENTITIES:
		logger.Println("getting files entities")
		if err = verifyFieldsString(req.Payload, "path", "userId", "section"); err != nil {
			return
		}
		var backward bool
		if err = verifyFieldsBool(req.Payload, "backward"); err == nil {
			backward = req.Payload["backward"].(bool)
		}
		if err = verifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
			return
		}
		err = zfh.GetFSEntities(req.Payload["userId"].(string), req.Payload["section"].(string), req.Payload["path"].(string), 0, 100, backward)
	case CREATE_FOLDER:
		logger.Println("creating folder")
		if err = verifyFieldsString(req.Payload, "path"); err != nil {
			return
		}
		if _, ok := req.Payload["config"]; !ok {
			err = fmt.Errorf("no field config in request payload")
			return
		}
		bs, jsonErr := json.Marshal(req.Payload["config"])
		if jsonErr != nil {
			return jsonErr
		}
		var config ZoneFSEntity
		if err = json.Unmarshal(bs, &config); err != nil {
			err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err)
			return
		}
		err = zfh.CreateFolder(req.Payload["path"].(string), &config)
	case RENAME_FOLDER:
		if err = verifyFieldsString(req.Payload, "path", "name", "newName"); err != nil {
			return
		}
		err = zfh.RenameFolder(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["newName"].(string))
	case RENAME_FILE:
		if err = verifyFieldsString(req.Payload, "path", "name", "newName"); err != nil {
			return
		}
		err = zfh.RenameFile(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["newName"].(string))
	case COPY_FOLDER:
		if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
			return
		}
		if _, ok := req.Payload["config"]; !ok {
			err = fmt.Errorf("no field config in request payload")
			return
		}
		bs, jsonErr := json.Marshal(req.Payload["config"])
		if jsonErr != nil {
			return jsonErr
		}
		var config ZoneFSEntity
		if err = json.Unmarshal(bs, &config); err != nil {
			err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err)
			return
		}
		go func() {
			err = zfh.CopyDir(req.Payload["path"].(string), req.Payload["dstPath"].(string), true, &config)
			logger.Println(err)
		}()
	case COPY_FILE:
		if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
			return
		}
		if _, ok := req.Payload["config"]; !ok {
			err = fmt.Errorf("no field config in request payload")
			return
		}
		bs, jsonErr := json.Marshal(req.Payload["config"])
		if jsonErr != nil {
			return jsonErr
		}
		var config ZoneFSEntity
		if err = json.Unmarshal(bs, &config); err != nil {
			err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err)
			return
		}
		go func() {
			err = zfh.CopyFile(req.Payload["path"].(string), req.Payload["dstPath"].(string), true, &config)
			logger.Println(err)
		}()
	case CUT_FOLDER:
		if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
			return
		}
		if _, ok := req.Payload["config"]; !ok {
			err = fmt.Errorf("no field config in request payload")
			return
		}
		bs, jsonErr := json.Marshal(req.Payload["config"])
		if jsonErr != nil {
			return jsonErr
		}
		var config ZoneFSEntity
		if err = json.Unmarshal(bs, &config); err != nil {
			err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err)
			return
		}
		go func() {
			err = zfh.CutFolder(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["dstPath"].(string), true, &config)
			logger.Println(err)
		}()
	case CUT_FILE:
		if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
			return
		}
		if _, ok := req.Payload["config"]; !ok {
			err = fmt.Errorf("no field config in request payload")
			return
		}
		bs, jsonErr := json.Marshal(req.Payload["config"])
		if jsonErr != nil {
			return jsonErr
		}
		var config ZoneFSEntity
		if err = json.Unmarshal(bs, &config); err != nil {
			err = fmt.Errorf("the config payload dont match ZoneFSEntity struct pattern : %v", err)
			return
		}
		go func() {
			err = zfh.CutFile(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["dstPath"].(string), true, &config)
			logger.Println(err)
		}()
	case UPDATE_PERMISSIONS:
		if err = verifyFieldsString(req.Payload, "path", "name", "userId"); err != nil {
			return
		}
		if err = verifyFieldsBool(req.Payload, "read", "write", "download", "rename"); err != nil {
			return
		}
		fsAcessRights := &FSEntityAccessRights{
			Read:     req.Payload["read"].(bool),
			Write:    req.Payload["write"].(bool),
			Download: req.Payload["download"].(bool),
			Rename:   req.Payload["rename"].(bool),
		}
		err = zfh.UpdatePermissions(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["userId"].(string), fsAcessRights)
	case DELETE_FOLDER:
		if err = verifyFieldsString(req.Payload, "path", "name"); err != nil {
			return
		}
		err = zfh.DeleteFolder(req.Payload["path"].(string), req.Payload["name"].(string))
	case DELETE_FILE:
		if err = verifyFieldsString(req.Payload, "path", "name"); err != nil {
			return
		}
		err = zfh.DeleteFile(req.Payload["path"].(string), req.Payload["name"].(string))
	case ADD_FS_ENTITY_MEMBERS:
		if err = verifyFieldsString(req.Payload, "path", "userId", "folderName"); err != nil {
			return
		}
		if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
			return
		}
		if err = verifyFieldsBool(req.Payload, "read", "write", "download", "rename"); err != nil {
			return
		}
		err = zfh.AddFolderMember(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["folderName"].(string), req.Payload["members"].([]interface{}), req.Payload["read"].(bool), req.Payload["write"].(bool), req.Payload["download"].(bool), req.Payload["rename"].(bool))
	case REMOVE_FS_ENTITY_MEMBERS:
		if err = verifyFieldsString(req.Payload, "path", "userId", "folderName"); err != nil {
			return
		}
		if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
			return
		}
		err = zfh.RemoveFolderMember(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["folderName"].(string), req.Payload["members"].([]interface{}))
	// case string(ZONE_FS_WEBRTC_OFFER):
	// 	if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
	// 		return
	// 	}
	// 	err = zfh.ConnectToFSInstance(req.Payload["channelId"].(string), req.Payload["userId"].(string), req.Payload["sdp"].(string))
	// case string(ZONE_FS_WEBRTC_COUNTER_OFFER):
	// 	logger.Println("handling fs instance counter offer")
	// 	if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
	// 		return
	// 	}
	// 	err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) {
	// 		err = zfh.FSInstance.HandleCounterOffer(context.Background(), req.Payload["userId"].(string), zfh.sendDataChannelMessage)
	// 		return
	// 	})
	// case string(ZONE_FS_WEBRTC_RENNEGOTIATION_OFFER):
	// 	if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
	// 		return
	// 	}
	// 	err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) {
	// 		err = zfh.FSInstance.HandleRennegotiationOffer(req.Payload["userId"].(string), req.Payload["sdp"].(string), zfh.sendDataChannelMessage)
	// 		return
	// 	})
	// case string(ZONE_FS_WEBRTC_RENNEGOTIATION_ANSWER):
	// 	if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
	// 		return
	// 	}
	// 	err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) {
	// 		err = zfh.FSInstance.HandleRennegotiationAnswer(req.Payload["userId"].(string), req.Payload["sdp"].(string))
	// 		return
	// 	})
	// case string(ZONE_FS_WEBRTC_CANDIDATE):
	// 	logger.Println("handling fs instance webrtc candidate")
	// 	logger.Println(req.Payload)
	// 	if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil {
	// 		return
	// 	}
	// 	logger.Println(req.Payload)
	// 	i, convErr := strconv.Atoi(req.Payload["sdpMLineIndex"].(string))
	// 	if convErr != nil {
	// 		return convErr
	// 	}
	// 	SDPMLineIndex := uint16(i)
	// 	sdpMid := req.Payload["sdpMid"].(string)
	// 	logger.Println(sdpMid, SDPMLineIndex)
	// 	err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) {
	// 		err = zfh.FSInstance.AddCandidate(&webrtc.ICECandidateInit{
	// 			Candidate:     req.Payload["candidate"].(string),
	// 			SDPMid:        &sdpMid,
	// 			SDPMLineIndex: &SDPMLineIndex,
	// 		}, req.Payload["userId"].(string))
	// 		return
	// 	})
	default:
		logger.Println("got your request in zone file handler", req)
		return
	}
	return
}
