package instrumentation

import (
	"github.com/grafana/grafana-plugin-sdk-go/backend"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

var (
	pluginRequestCounter = promauto.NewCounterVec(prometheus.CounterOpts{
		Namespace: "grafana",
		Name:      "prometheus_plugin_backend_request_count",
		Help:      "The total amount of prometheus backend plugin requests",
	}, []string{"endpoint", "status", "errorSource"})
)

const (
	StatusOK    = "ok"
	StatusError = "error"

	EndpointCallResource = string(backend.EndpointCallResource)
	EndpointQueryData    = string(backend.EndpointQueryData)

	PluginSource   = "plugin"
	ExternalSource = "external"
	DatabaseSource = "database"
	NoneSource     = "none"
)

func UpdateQueryDataMetrics(err error, resp *backend.QueryDataResponse) {
	status := StatusOK
	if err != nil {
		status = StatusError
	}

	errorSource := getErrorSource(err, resp)

	pluginRequestCounter.WithLabelValues(EndpointQueryData, status, errorSource).Inc()
}

func getErrorSource(err error, resp *backend.QueryDataResponse) string {
	if err != nil {
		return PluginSource
	}

	// If there is different errorSource from the list of responses, we want to return the most severe one.
	// The priority order is: pluginSource > databaseSource > externalSource > noneSource
	var errorSource = NoneSource
	for _, res := range resp.Responses {
		responseErrorSource := getErrorSourceForResponse(res)

		if responseErrorSource == PluginSource {
			return PluginSource
		}

		if responseErrorSource == DatabaseSource {
			errorSource = DatabaseSource
		}

		if responseErrorSource == ExternalSource && errorSource == NoneSource {
			errorSource = ExternalSource
		}
	}

	return errorSource
}

func getErrorSourceForResponse(res backend.DataResponse) string {
	if res.Error != nil {
		return PluginSource
	}

	if res.Status >= 500 {
		return DatabaseSource
	}

	if res.Status >= 400 {
		// Those error codes are related to authentication and authorization.
		if res.Status == 401 || res.Status == 402 || res.Status == 403 || res.Status == 407 {
			return ExternalSource
		}

		return PluginSource
	}

	return NoneSource
}
