package telemetrymetrics

import (
	"errors"
	"time"

	identifier "code.justin.tv/amzn/TwitchProcessIdentifier"
	telemetry "code.justin.tv/amzn/TwitchTelemetry"
	"code.justin.tv/hygienic/spade"
)

// Reporter sends metrics
type Reporter struct {
	SampleReporter *telemetry.SampleReporter
}

// RequestCount is called any time a spade request is made
func (r *Reporter) RequestCount() {
	r.reportCount("Spade_RequestCount", 1)
}

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

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

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

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

// reportOperation sends dependency metrics similar to the pattern in amzn/TwitchTelemetryMetricsMiddleware
func (r *Reporter) reportOperation(operationName string, dur time.Duration, err error) {
	if r.SampleReporter == nil {
		return
	}

	// Create a copy of struct (convention to change dimensions)
	var reporter telemetry.SampleReporter
	reporter = *r.SampleReporter

	reporter.DependencyProcessIdentifier = identifier.ProcessIdentifier{
		Service: "Spade",
	}
	reporter.DependencyOperationName = operationName

	availabilityCode := telemetry.AvailabilityCodeSucccess

	if err != nil {
		availabilityCode = telemetry.AvailabilityCodeClientError

		var httpError spade.HTTPError
		if errors.As(err, &httpError) {
			if httpError.StatusCode >= 500 {
				availabilityCode = telemetry.AvailabilityCodeServerError
			}
		}
	}

	reporter.ReportDurationSample(telemetry.MetricDependencyDuration, dur)
	reporter.ReportAvailabilitySamples(availabilityCode)
}

func (r *Reporter) reportCount(metricName string, value int64) {
	if r.SampleReporter == nil {
		return
	}

	r.SampleReporter.Report(metricName, float64(value), telemetry.UnitCount)
}

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