package view

import (
	"encoding/json"
	"errors"
	"fmt"
	"local/dndex/config"
	"local/dndex/storage"
	"local/gziphttp"
	"log"
	"net/http"
	"strings"
)

func JSON(g storage.Graph) error {
	port := config.New().Port
	log.Println("listening on", port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", port), jsonHandler(g))
	return err
}

func jsonHandler(g storage.Graph) http.Handler {
	mux := http.NewServeMux()

	routes := []struct {
		path   string
		foo    func(g storage.Graph, w http.ResponseWriter, r *http.Request) error
		noauth bool
	}{
		{
			path: "/who",
			foo:  who,
		},
		{
			path:   "/register",
			foo:    register,
			noauth: true,
		},
		{
			path: config.New().FilePrefix + "/",
			foo:  files,
		},
	}

	for _, route := range routes {
		foo := route.foo
		auth := !route.noauth
		mux.HandleFunc(route.path, func(w http.ResponseWriter, r *http.Request) {
			if auth {
				if err := Auth(g, w, r); err != nil {
					return
				}
			}
			if err := foo(g, w, r); err != nil {
				status := http.StatusInternalServerError
				if strings.Contains(err.Error(), "collision") {
					status = http.StatusConflict
				}
				b, _ := json.Marshal(map[string]string{"error": err.Error()})
				http.Error(w, string(b), status)
			}
		})
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if gziphttp.Can(r) {
			gz := gziphttp.New(w)
			defer gz.Close()
			w = gz
		}
		mux.ServeHTTP(w, r)
	})
}

func getAuthNamespace(r *http.Request) (string, error) {
	namespace := r.URL.Query().Get("namespace")
	if len(namespace) == 0 {
		return "", errors.New("no namespace found")
	}
	return strings.Join([]string{namespace, AuthKey}, "."), nil
}

func getNamespace(r *http.Request) (string, error) {
	namespace := r.URL.Query().Get("namespace")
	if len(namespace) == 0 {
		return "", errors.New("no namespace found")
	}
	return namespace, nil
}
