"fmt"
	"github.com/kawamuray/prometheus-exporter-harness/harness"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/urfave/cli"
)

type ScrapeType struct {
	Configure  func(*Config, *harness.MetricRegistry)
	NewScraper func(*Config) (JsonScraper, error)
}

var ScrapeTypes = map[string]*ScrapeType{
	"object": {
		Configure: func(config *Config, reg *harness.MetricRegistry) {
			for subName := range config.Values {
				name := harness.MakeMetricName(config.Name, subName)
				reg.Register(
					name,
					prometheus.NewGaugeVec(prometheus.GaugeOpts{
						Name: name,
						Help: config.Help + " - " + subName,
					}, config.labelNames()),
				)
			}
		},
		NewScraper: NewObjectScraper,
	},
	"value": {
		Configure: func(config *Config, reg *harness.MetricRegistry) {
			reg.Register(
				config.Name,
func (obsc *ObjectScraper) Scrape(data []byte, reg *harness.MetricRegistry) error {
	return obsc.forTargetValue(data, func(result *jsonpath.Result) {
		if result.Type != jsonpath.JsonObject && result.Type != jsonpath.JsonArray {
			log.Warnf("skipping not structual result;path:<%s>,value:<%s>",
				obsc.valueJsonPath, result.Value)
			return
		}

		labels := obsc.newLabels()
		for name, path := range obsc.labelJsonPaths {
			firstResult, err := obsc.extractFirstValue(result.Value, path)
			if err != nil {
				log.Warnf("could not find value for label path;path:<%s>,json:<%s>,err:<%s>", path, result.Value, err)
				continue
			}
			value := firstResult.Value
			if firstResult.Type == jsonpath.JsonString {
				// Strip quotes
				value = value[1 : len(value)-1]
			}
			labels[name] = string(value)
		}

		for name, configValue := range obsc.Values {
			var metricValue float64
			path := obsc.valueJsonPaths[name]

			if path == nil {
				// Static value
				value, err := obsc.parseValue([]byte(configValue))
				if err != nil {
					log.Errorf("could not use configured value as float number;name:<%s>,err:<%s>", err)
					continue
				}
				metricValue = value
			} else {
				// Dynamic value
				firstResult, err := obsc.extractFirstValue(result.Value, path)
				if err != nil {
					log.Warnf("could not find value for value path;path:<%s>,json:<%s>,err:<%s>", path, result.Value, err)
					continue
				}

				if firstResult.Type != jsonpath.JsonNumber {
					log.Warnf("skipping not numerical result;path:<%s>,value:<%s>",
						obsc.valueJsonPath, result.Value)
					continue
				}

				value, err := obsc.parseValue(firstResult.Value)
				if err != nil {
					// Should never happen.
					log.Errorf("could not parse numerical value as float;path:<%s>,value:<%s>",
						obsc.valueJsonPath, firstResult.Value)
					continue
				}
				metricValue = value
			}

			fqn := harness.MakeMetricName(obsc.Name, name)
			log.Debugf("metric updated;name:<%s>,labels:<%s>,value:<%.2f>", fqn, labels, metricValue)
			reg.Get(fqn).(*prometheus.GaugeVec).With(labels).Set(metricValue)
		}
	})
}