package common

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"

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

// GetExtraLabels extracts name:value labels from `extra_label=name=value` query args from req.
//
// It also extracts Pushgateways-compatible extra labels from req.URL.Path
// according to https://github.com/prometheus/pushgateway#url .
func GetExtraLabels(req *http.Request) ([]prompbmarshal.Label, error) {
	labels, err := getPushgatewayLabels(req.URL.Path)
	if err != nil {
		return nil, fmt.Errorf("cannot parse pushgateway-style labels from %q: %w", req.URL.Path, err)
	}
	q := req.URL.Query()
	for _, label := range q["extra_label"] {
		tmp := strings.SplitN(label, "=", 2)
		if len(tmp) != 2 {
			return nil, fmt.Errorf("`extra_label` query arg must have the format `name=value`; got %q", label)
		}
		labels = append(labels, prompbmarshal.Label{
			Name:  tmp[0],
			Value: tmp[1],
		})
	}
	return labels, nil
}

func getPushgatewayLabels(path string) ([]prompbmarshal.Label, error) {
	n := strings.Index(path, "/metrics/job")
	if n < 0 {
		return nil, nil
	}
	s := path[n+len("/metrics/"):]
	if !strings.HasPrefix(s, "job/") && !strings.HasPrefix(s, "job@base64/") {
		return nil, nil
	}
	labelsCount := (strings.Count(s, "/") + 1) / 2
	labels := make([]prompbmarshal.Label, 0, labelsCount)
	for len(s) > 0 {
		n := strings.IndexByte(s, '/')
		if n < 0 {
			return nil, fmt.Errorf("missing value for label %q", s)
		}
		name := s[:n]
		s = s[n+1:]
		isBase64 := strings.HasSuffix(name, "@base64")
		if isBase64 {
			name = name[:len(name)-len("@base64")]
		}
		var value string
		n = strings.IndexByte(s, '/')
		if n < 0 {
			value = s
			s = ""
		} else {
			value = s[:n]
			s = s[n+1:]
		}
		if isBase64 {
			data, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(value, "="))
			if err != nil {
				return nil, fmt.Errorf("cannot base64-decode value=%q for label=%q: %w", value, name, err)
			}
			value = string(data)
		}
		if len(value) == 0 {
			// Skip labels with empty values
			continue
		}
		labels = append(labels, prompbmarshal.Label{
			Name:  name,
			Value: value,
		})
	}
	return labels, nil
}