package statsdmetrics

import (
	"time"

	"code.justin.tv/hygienic/spade"
)

type statSender interface {
	Inc(string, int64, float32) error
	TimingDuration(string, time.Duration, float32) error
}

type logger interface {
	Log(vals ...interface{})
}

// Reporter reports metrics to statsd
type Reporter struct {
	// Statter sends statsd metrics
	Statter statSender
	// Logger is optional
	Logger logger
	// SampleRate defaults to .1
	SampleRate float32
}

// RequestCount is called any time a spade request is made
func (r *Reporter) RequestCount() {
	r.inc("message.request_count", 1, r.sampleRate())
}

// SendSuccess is called when a successful spade request happens. The HTTP response is an 204 (NoContent)
func (r *Reporter) SendSuccess(duration time.Duration) {
	r.timingDuration("send.success", duration, r.sampleRate())
}

// SendFailure is called when a spade request fails for any reason
func (r *Reporter) SendFailure(duration time.Duration, err error) {
	r.timingDuration("send.fail", duration, r.sampleRate())
}

// Events is called with the number of events sent in a successful request
func (r *Reporter) Events(eventCount int) {
	r.inc("events", int64(eventCount), r.sampleRate())
}

// BacklogFull is called when the backlog is full and cannot queue more events
func (r *Reporter) BacklogFull() {
	r.inc("errors.backlog_full", 1, r.sampleRate())
}

func (r *Reporter) log(vals ...interface{}) {
	if r.Logger != nil {
		r.Logger.Log(vals...)
	}
}

func (r *Reporter) sampleRate() float32 {
	if r.SampleRate <= 0 {
		return 0.1
	}

	return r.SampleRate
}

func (r *Reporter) inc(stat string, value int64, rate float32) {
	if r.Statter == nil {
		return
	}

	err := r.Statter.Inc(stat, value, rate)
	if err != nil {
		r.log("err", "failure sending stats", "staterr", err)
	}
}

func (r *Reporter) timingDuration(stat string, dur time.Duration, rate float32) {
	if r.Statter == nil {
		return
	}

	err := r.Statter.TimingDuration(stat, dur, rate)
	if err != nil {
		r.log("err", "failure sending stats", "staterr", err)
	}
}

var _ spade.Reporter = (*Reporter)(nil)
