package main

import (
	// External
	"git.ahall.se/go/html_template"

	// Standard
	"encoding/json"
	"fmt"
	"io"
	"io/fs"
	"net/http"
	"strconv"
)

var (
	engine HTMLTemplate.Engine
)

func initWebserver() (err error) {
	address := fmt.Sprintf("%s:%d", config.Network.Address, config.Network.Port)
	logger.Info("webserver", "listen", address)

	subViewFS, _ := fs.Sub(viewFS, "views")
	subStaticFS, _ := fs.Sub(staticFS, "static")

	engine, err = HTMLTemplate.NewEngine(subViewFS, subStaticFS, flagDev)
	if err != nil {
		return
	}

	http.HandleFunc("/", pageIndex)
	http.HandleFunc("/app", pageApp)
	http.HandleFunc("/nodes/tree/{startNode}", actionNodesTree)
	http.HandleFunc("/nodes/{nodeID}", actionNode)
	http.HandleFunc("/nodes/update/{nodeID}", actionNodeUpdate)
	http.HandleFunc("/types/{typeID}", actionType)
	http.HandleFunc("/types/", actionTypesAll)

	err = http.ListenAndServe(address, nil)
	return
}

func httpError(w http.ResponseWriter, err error) { // {{{
	out := struct {
		OK    bool
		Error string
	}{
		false,
		err.Error(),
	}
	j, _ := json.Marshal(out)
	w.Write(j)
} // }}}

func pageIndex(w http.ResponseWriter, r *http.Request) { // {{{
	if r.URL.Path == "/" {
		http.Redirect(w, r, "/app", http.StatusSeeOther)
	} else {
		engine.StaticResource(w, r)
	}
} // }}}
func pageApp(w http.ResponseWriter, r *http.Request) { // {{{
	page := NewPage("app")
	err := engine.Render(page, w, r)
	if err != nil {
		w.Write([]byte(err.Error()))
	}
} // }}}

func actionNodesTree(w http.ResponseWriter, r *http.Request) { // {{{
	var err error

	startNode := 0
	startNodeStr := r.PathValue("startNode")
	startNode, _ = strconv.Atoi(startNodeStr)

	var maxDepth int
	if maxDepth, err = strconv.Atoi(r.URL.Query().Get("depth")); err != nil {
		maxDepth = 3
	}

	topNode, err := GetNodeTree(startNode, maxDepth)
	if err != nil {
		httpError(w, err)
		return
	}

	out := struct {
		OK    bool
		Nodes *Node
	}{
		true,
		topNode,
	}

	j, _ := json.Marshal(out)
	w.Write(j)
} // }}}
func actionNode(w http.ResponseWriter, r *http.Request) { // {{{
	nodeID := 0
	nodeIDStr := r.PathValue("nodeID")
	nodeID, _ = strconv.Atoi(nodeIDStr)

	node, err := GetNode(nodeID)
	if err != nil {
		httpError(w, err)
		return
	}

	out := struct {
		OK   bool
		Node Node
	}{
		true,
		node,
	}
	j, _ := json.Marshal(out)
	w.Write(j)
} // }}}
func actionNodeUpdate(w http.ResponseWriter, r *http.Request) { // {{{
	nodeID := 0
	nodeIDStr := r.PathValue("nodeID")
	nodeID, _ = strconv.Atoi(nodeIDStr)

	data, _ := io.ReadAll(r.Body)

	err := UpdateNode(nodeID, data)
	if err != nil {
		httpError(w, err)
		return
	}

	out := struct {
		OK   bool
	}{
		true,
	}
	j, _ := json.Marshal(out)
	w.Write(j)
} // }}}
func actionType(w http.ResponseWriter, r *http.Request) { // {{{
	typeID := 0
	typeIDStr := r.PathValue("typeID")
	typeID, _ = strconv.Atoi(typeIDStr)

	typ, err := GetType(typeID)
	if err != nil {
		httpError(w, err)
		return
	}

	j, _ := json.Marshal(typ)
	w.Write(j)
} // }}}
func actionTypesAll(w http.ResponseWriter, r *http.Request) { // {{{
	types, err := GetTypes()
	if err != nil {
		httpError(w, err)
		return
	}

	out := struct {
		OK bool
		Types []NodeType
	}{
		true,
		types,
	}

	j, _ := json.Marshal(out)
	w.Write(j)
} // }}}

// vim: foldmethod=marker
