//go:build unix

package nfs

import (
	"context"
	"fmt"
	"net"

	nfs "github.com/willscott/go-nfs"

	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/vfs"
	"github.com/rclone/rclone/vfs/vfscommon"
)

// Server contains everything to run the Server
type Server struct {
	opt                 Options
	handler             nfs.Handler
	ctx                 context.Context // for global config
	listener            net.Listener
	UnmountedExternally bool
}

// NewServer creates a new server
func NewServer(ctx context.Context, vfs *vfs.VFS, opt *Options) (s *Server, err error) {
	if vfs.Opt.CacheMode == vfscommon.CacheModeOff {
		fs.LogPrintf(fs.LogLevelWarning, ctx, "NFS writes don't work without a cache, the filesystem will be served read-only")
	}
	// Our NFS server doesn't have any authentication, we run it on localhost and random port by default
	if opt.ListenAddr == "" {
		opt.ListenAddr = "localhost:"
	}

	s = &Server{
		ctx: ctx,
		opt: *opt,
	}
	s.handler, err = NewHandler(ctx, vfs, opt)
	if err != nil {
		return nil, fmt.Errorf("failed to make NFS handler: %w", err)
	}
	s.listener, err = net.Listen("tcp", s.opt.ListenAddr)
	if err != nil {
		return nil, fmt.Errorf("failed to open listening socket: %w", err)
	}
	return s, nil
}

// Addr returns the listening address of the server
func (s *Server) Addr() net.Addr {
	return s.listener.Addr()
}

// Shutdown stops the server
func (s *Server) Shutdown() error {
	return s.listener.Close()
}

// Serve starts the server
func (s *Server) Serve() (err error) {
	fs.Logf(nil, "NFS Server running at %s\n", s.listener.Addr())
	return nfs.Serve(s.listener, s.handler)
}
