// +build windows

package cache_test

import (
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/billziss-gh/cgofuse/fuse"
	"github.com/ncw/rclone/cmd/cmount"
	"github.com/ncw/rclone/cmd/mountlib"
	"github.com/ncw/rclone/fs"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/require"
)

// waitFor runs fn() until it returns true or the timeout expires
func waitFor(fn func() bool) (ok bool) {
	const totalWait = 10 * time.Second
	const individualWait = 10 * time.Millisecond
	for i := 0; i < int(totalWait/individualWait); i++ {
		ok = fn()
		if ok {
			return ok
		}
		time.Sleep(individualWait)
	}
	return false
}

func (r *run) mountFs(t *testing.T, f fs.Fs) {
	// FIXME implement cmount
	t.Skip("windows not supported yet")

	device := f.Name() + ":" + f.Root()
	options := []string{
		"-o", "fsname=" + device,
		"-o", "subtype=rclone",
		"-o", fmt.Sprintf("max_readahead=%d", mountlib.MaxReadAhead),
		"-o", "uid=-1",
		"-o", "gid=-1",
		"-o", "allow_other",
		// This causes FUSE to supply O_TRUNC with the Open
		// call which is more efficient for cmount.  However
		// it does not work with cgofuse on Windows with
		// WinFSP so cmount must work with or without it.
		"-o", "atomic_o_trunc",
		"--FileSystemName=rclone",
	}

	fsys := cmount.NewFS(f)
	host := fuse.NewFileSystemHost(fsys)

	// Serve the mount point in the background returning error to errChan
	r.unmountRes = make(chan error, 1)
	go func() {
		var err error
		ok := host.Mount(r.mntDir, options)
		if !ok {
			err = errors.New("mount failed")
		}
		r.unmountRes <- err
	}()

	// unmount
	r.unmountFn = func() error {
		// Shutdown the VFS
		fsys.VFS.Shutdown()
		if host.Unmount() {
			if !waitFor(func() bool {
				_, err := os.Stat(r.mntDir)
				return err != nil
			}) {
				t.Fatalf("mountpoint %q didn't disappear after unmount - continuing anyway", r.mntDir)
			}
			return nil
		}
		return errors.New("host unmount failed")
	}

	// Wait for the filesystem to become ready, checking the file
	// system didn't blow up before starting
	select {
	case err := <-r.unmountRes:
		require.NoError(t, err)
	case <-time.After(time.Second * 3):
	}

	// Wait for the mount point to be available on Windows
	// On Windows the Init signal comes slightly before the mount is ready
	if !waitFor(func() bool {
		_, err := os.Stat(r.mntDir)
		return err == nil
	}) {
		t.Errorf("mountpoint %q didn't became available on mount", r.mntDir)
	}

	r.vfs = fsys.VFS
	r.isMounted = true
}

func (r *run) unmountFs(t *testing.T, f fs.Fs) {
	// FIXME implement cmount
	t.Skip("windows not supported yet")
	var err error

	for i := 0; i < 4; i++ {
		err = r.unmountFn()
		if err != nil {
			//log.Printf("signal to umount failed - retrying: %v", err)
			time.Sleep(3 * time.Second)
			continue
		}
		break
	}
	require.NoError(t, err)
	err = <-r.unmountRes
	require.NoError(t, err)
	err = r.vfs.CleanUp()
	require.NoError(t, err)
	r.isMounted = false
}