package exporter

import (
	"fmt"
	"strings"

	"github.com/prometheus/client_golang/prometheus"
)

/* ================ Column ================ */

const (
	DISCARD   = "DISCARD"   // Ignore this column (when SELECT *)
	LABEL     = "LABEL"     // Use this column as a label
	COUNTER   = "COUNTER"   // Use this column as a counter
	GAUGE     = "GAUGE"     // Use this column as a gauge
	HISTOGRAM = "HISTOGRAM" // Use this column as a histogram
)

// ColumnUsage determine how to use query result column
var ColumnUsage = map[string]bool{
	DISCARD:   false,
	LABEL:     false,
	COUNTER:   true,
	GAUGE:     true,
	HISTOGRAM: true,
}

// Column holds the metadata of query result
type Column struct {
	Name    string    `yaml:"name"`
	Usage   string    `yaml:"usage,omitempty"`   // column usage
	Rename  string    `yaml:"rename,omitempty"`  // rename column
	Bucket  []float64 `yaml:"bucket,omitempty"`  // histogram bucket
	Scale   string    `yaml:"scale,omitempty"`   // scale factor
	Default string    `yaml:"default,omitempty"` // default value
	Desc    string    `yaml:"description,omitempty"`
}

// PrometheusValueType returns column's corresponding prometheus value type
func (c *Column) PrometheusValueType() prometheus.ValueType {
	switch strings.ToUpper(c.Usage) {
	case GAUGE:
		return prometheus.GaugeValue
	case COUNTER:
		return prometheus.CounterValue
	default:
		// it's user's responsibility to make sure this is a value column
		panic(fmt.Errorf("column %s does not have a valid value type %s", c.Name, c.Usage))
	}
}

// String turns column into a one-line text representation
func (c *Column) String() string {
	return fmt.Sprintf("%-8s %-20s %s", c.Usage, c.Name, c.Desc)
}

// MetricDesc will generate MetricDesc from column and additional information
func (c *Column) MetricDesc(prefix string, labels []string) *MetricDesc {
	metricName := fmt.Sprintf("%s_%s{%s}", prefix, c.Name, strings.Join(labels, ","))
	if c.Rename != "" {
		metricName = fmt.Sprintf("%s_%s{%s}", prefix, c.Rename, labels)
	}
	return &MetricDesc{
		metricName,
		labels,
		c,
	}
}

// MetricDesc is generated by collector's column definition
type MetricDesc struct {
	Name   string
	Labels []string
	Column *Column
}

// Signature will print metric signature such as pg_db_age{datname}
func (m *MetricDesc) String() string {
	return fmt.Sprintf("%s %-8s %s", m.Name, m.Column.Usage, m.Column.Desc)
}
