package ctrl

import (
	"net/http"
	"path/filepath"
	"strings"

	. "github.com/mickael-kerjean/filestash/server/common"
	"github.com/mickael-kerjean/filestash/server/model"
	"github.com/mickael-kerjean/net/webdav"
)

func WebdavHandler(ctx *App, res http.ResponseWriter, req *http.Request) {
	if ctx.Share.Id == "" {
		http.NotFound(res, req)
		return
	}

	// https://github.com/golang/net/blob/master/webdav/webdav.go#L49-L68
	canRead := model.CanRead(ctx)
	canWrite := model.CanEdit(ctx)
	canUpload := model.CanUpload(ctx)
	switch req.Method {
	case "OPTIONS", "HEAD", "GET":
		if canRead == false {
			SendErrorResult(res, ErrPermissionDenied)
			return
		}
	case "MKCOL", "DELETE", "COPY", "MOVE", "PROPPATCH":
		if canWrite == false {
			SendErrorResult(res, ErrPermissionDenied)
			return
		}
	case "PROPFIND":
		if canRead == false {
			SendErrorResult(res, ErrPermissionDenied)
			return
		}
	case "PUT":
		if canWrite == false || canUpload == false {
			SendErrorResult(res, ErrPermissionDenied)
			return
		}
	case "LOCK", "UNLOCK":
		if canWrite == false || canUpload == false {
			SendErrorResult(res, ErrPermissionDenied)
			return
		}
	default:
		SendErrorResult(res, ErrNotImplemented)
		return
	}

	h := &webdav.Handler{
		Prefix:     "/s/" + ctx.Share.Id,
		FileSystem: model.NewWebdavFs(ctx.Backend, ctx.Share.Backend, ctx.Share.Path, req),
		LockSystem: model.NewWebdavLock(),
	}
	h.ServeHTTP(res, req)
}

/*
 * OSX ask for a lot of crap while mounting as a network drive. To avoid wasting resources with such
 * an imbecile and considering we can't even see the source code they are running, the best approach we
 * could go on is: "crap in, crap out" where useless request coming in are identified and answer appropriatly
 */
func WebdavBlacklist(fn HandlerFunc) HandlerFunc {
	return HandlerFunc(func(ctx *App, res http.ResponseWriter, req *http.Request) {
		base := filepath.Base(req.URL.String())

		if req.Method == "PUT" || req.Method == "MKCOL" {
			if strings.HasPrefix(base, "._") {
				res.WriteHeader(http.StatusMethodNotAllowed)
				res.Write([]byte(""))
				return
			} else if base == ".DS_Store" {
				res.WriteHeader(http.StatusMethodNotAllowed)
				res.Write([]byte(""))
				return
			} else if base == ".localized" {
				res.WriteHeader(http.StatusMethodNotAllowed)
				res.Write([]byte(""))
				return
			}
		} else if req.Method == "PROPFIND" {
			if strings.HasPrefix(base, "._") {
				res.WriteHeader(http.StatusForbidden)
				return
			} else if base == ".DS_Store" {
				res.WriteHeader(http.StatusForbidden)
				res.Write([]byte(""))
				return
			} else if base == ".localized" {
				res.WriteHeader(http.StatusForbidden)
				return
			} else if base == ".ql_disablethumbnails" {
				res.WriteHeader(http.StatusForbidden)
				res.Write([]byte(""))
				return
			} else if base == ".ql_disablecache" {
				res.WriteHeader(http.StatusForbidden)
				return
			} else if base == ".hidden" {
				res.WriteHeader(http.StatusForbidden)
				return
			} else if base == ".Spotlight-V100" {
				res.WriteHeader(http.StatusForbidden)
				return
			} else if base == ".metadata_never_index" {
				res.WriteHeader(http.StatusForbidden)
				return
			} else if base == "Contents" {
				res.WriteHeader(http.StatusForbidden)
				return
			} else if base == ".metadata_never_index_unless_rootfs" {
				res.WriteHeader(http.StatusForbidden)
				return
			}
		} else if req.Method == "GET" {
			if base == ".DS_Store" {
				res.WriteHeader(http.StatusForbidden)
				res.Write([]byte(""))
				return
			}
		} else if req.Method == "DELETE" {
			if base == ".DS_Store" {
				res.WriteHeader(http.StatusForbidden)
				res.Write([]byte(""))
				return
			}
		} else if req.Method == "LOCK" || req.Method == "UNLOCK" {
			if base == ".DS_Store" {
				res.WriteHeader(http.StatusMethodNotAllowed)
				res.Write([]byte(""))
				return
			}
		}
		fn(ctx, res, req)
	})
}
