package graphite

import (
	// embed functions.json file
	_ "embed"
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils"
)

// FunctionsHandler implements /functions handler.
//
// See https://graphite.readthedocs.io/en/latest/functions.html#function-api
func FunctionsHandler(w http.ResponseWriter, r *http.Request) error {
	grouped := httputils.GetBool(r, "grouped")
	group := r.FormValue("group")
	result := make(map[string]any)
	for funcName, fi := range funcs {
		if group != "" && fi.Group != group {
			continue
		}
		if grouped {
			v := result[fi.Group]
			if v == nil {
				v = make(map[string]*funcInfo)
				result[fi.Group] = v
			}
			m := v.(map[string]*funcInfo)
			m[funcName] = fi
		} else {
			result[funcName] = fi
		}
	}
	return writeJSON(result, w, r)
}

// FunctionDetailsHandler implements /functions/<func_name> handler.
//
// See https://graphite.readthedocs.io/en/latest/functions.html#function-api
func FunctionDetailsHandler(funcName string, w http.ResponseWriter, r *http.Request) error {
	result := funcs[funcName]
	if result == nil {
		return fmt.Errorf("cannot find function %q", funcName)
	}
	return writeJSON(result, w, r)
}

func writeJSON(result any, w http.ResponseWriter, r *http.Request) error {
	data, err := json.Marshal(result)
	if err != nil {
		return fmt.Errorf("cannot marshal response to JSON: %w", err)
	}
	jsonp := r.FormValue("jsonp")
	contentType := getContentType(jsonp)
	w.Header().Set("Content-Type", contentType)
	if jsonp != "" {
		fmt.Fprintf(w, "%s(", jsonp)
	}
	w.Write(data)
	if jsonp != "" {
		fmt.Fprintf(w, ")")
	}
	return nil
}

//go:embed functions.json
var funcsJSON []byte

type funcInfo struct {
	Name        string          `json:"name"`
	Function    string          `json:"function"`
	Description string          `json:"description"`
	Module      string          `json:"module"`
	Group       string          `json:"group"`
	Params      json.RawMessage `json:"params"`
}

var funcs = func() map[string]*funcInfo {
	var m map[string]*funcInfo
	if err := json.Unmarshal(funcsJSON, &m); err != nil {
		// Do not use logger.Panicf, since it isn't ready yet.
		panic(fmt.Errorf("cannot parse funcsJSON: %w", err))
	}
	return m
}()