package bokofs

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"sync"
	"time"

	"golang.org/x/net/webdav"
	"imuslab.com/bokofs/bokofsd/mod/bokofs/bokoworker"
)

/*
	WebDAV module

	This module handle the interfacing to the underlying file system
	through the middle ware
*/

type Options struct {
	ListeningAddress string //Listening address, e.g. 0.0.0.0:8443
	SecureServe      bool   //Use TLS to serve the WebDAV request
	PublicKeyPath    string
	PrivateKeyPath   string
}

type Server struct {
	LoadedWorkers sync.Map //Storing uuid to bokoworker pointer (*bokoworker.Worker)
	RootRouter    FlowRouter
	Options       *Options
}

/* NewWebdavInterfaceServer creates a new WebDAV server instance */
func NewWebdavInterfaceServer(options Options) (*Server, error) {
	thisServer := Server{
		LoadedWorkers: sync.Map{},
		Options:       &options,
	}

	//TODO: Load all the middlewares

	//Initiate the root router file system
	err := thisServer.InitiateRootRouter()
	if err != nil {
		return nil, err
	}

	return &thisServer, nil
}

func (s *Server) AddWorker(worker *bokoworker.Worker) {
	s.LoadedWorkers.Store(worker.RootPath, worker)
}

func (s *Server) RemoveWorker(workerRootPath string) {
	s.LoadedWorkers.Delete(workerRootPath)
}

func (s *Server) Start() error {
	srv := &webdav.Handler{
		FileSystem: s.RootRouter,
		LockSystem: webdav.NewMemLS(),
		Logger: func(r *http.Request, err error) {
			if err != nil {
				log.Printf("WEBDAV [%s]: %s, ERROR: %s\n", r.Method, r.URL, err)
			} else {
				log.Printf("WEBDAV [%s]: %s \n", r.Method, r.URL)
			}
		},
	}

	http.Handle("/", srv)

	if s.Options.SecureServe {
		if _, err := os.Stat(s.Options.PublicKeyPath); err != nil {
			fmt.Println("Public ket not found")
			return err
		}
		if _, err := os.Stat(s.Options.PrivateKeyPath); err != nil {
			fmt.Println("Private key not found")
			return err
		}
	}

	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()
	done := make(chan error)

	go func() {
		if s.Options.SecureServe {
			if err := http.ListenAndServeTLS(s.Options.ListeningAddress, s.Options.PublicKeyPath, s.Options.PrivateKeyPath, nil); err != nil {
				done <- err
			}
		} else {
			if err := http.ListenAndServe(s.Options.ListeningAddress, nil); err != nil {
				log.Fatalf("Error with WebDAV server: %v", err)
				done <- err
			}
		}
	}()

	select {
	case <-ctx.Done():
		//No error in 3 seconds. Assume all green
		return nil
	case success := <-done:
		if success != nil {
			log.Fatalf("Error with WebDAV server")
			return success
		}
	}
	return nil
}