package metrics

import (
	"context"
	"time"

	telemetry "code.justin.tv/amzn/TwitchTelemetry"
	poller "code.justin.tv/amzn/TwitchTelemetryPollingCollector"
	"code.justin.tv/eventbus/controlplane/internal/db"
	"code.justin.tv/eventbus/controlplane/internal/logger"
	"code.justin.tv/eventbus/fultonlog"
)

// Use a singleton to ensure that we never accidentally double (or worse) submit these metrics
var reportingCollector *poller.PollingCollector

// InitializeReporting creates a reporting polling job and starts it, submitting
// metrics for observations every 1 minute. The poller is returned, but note that
// the caller does not need to call Start() on the returned PollingCollector
func InitializeReporting(dbConn db.DB, l *logger.Logger) *poller.PollingCollector {
	// is the reporter already running?
	if reportingCollector != nil {
		if !reportingCollector.IsRunning() {
			reportingCollector.Start()
		}
		return reportingCollector
	}

	job := &ReportPollingJob{
		db: dbConn,
	}
	interval := time.Minute
	builder := &telemetry.SampleBuilder{
		ProcessIdentifier: ProcessIdentifier(),
	}
	reportingCollector = poller.NewPollingCollector(
		job,
		interval,
		builder,
		Observer(),
		fultonlog.FromZapLogger(l.Logger),
	)
	reportingCollector.Start()
	return reportingCollector
}

// ReportPollingJob is the business logic that is in charge of fetching and crafting
// base samples to be reported by the reporting PollingCollector harness
type ReportPollingJob struct {
	db db.DB
}

func (j *ReportPollingJob) Fetch() ([]*telemetry.Sample, error) {
	ctx := context.Background()
	samples := make([]*telemetry.Sample, 0, 4)

	svcs, err := j.db.Services(ctx)
	if err != nil {
		return nil, err
	}
	samples = append(samples, &telemetry.Sample{
		MetricID: *telemetry.NewMetricID("Services"),
		Value:    float64(len(svcs)),
		Unit:     telemetry.UnitCount,
	})

	targets, err := j.db.SubscriptionTargets(ctx)
	if err != nil {
		return nil, err
	}
	samples = append(samples, &telemetry.Sample{
		MetricID: *telemetry.NewMetricID("SubscriptionTargets"),
		Value:    float64(len(targets)),
		Unit:     telemetry.UnitCount,
	})

	subs, err := j.db.Subscriptions(ctx)
	if err != nil {
		return nil, err
	}
	samples = append(samples, &telemetry.Sample{
		MetricID: *telemetry.NewMetricID("Subscriptions"),
		Value:    float64(len(subs)),
		Unit:     telemetry.UnitCount,
	})

	eventTypes, err := j.db.EventTypes(ctx)
	if err != nil {
		return nil, err
	}
	samples = append(samples, &telemetry.Sample{
		MetricID: *telemetry.NewMetricID("EventTypes"),
		Value:    float64(len(eventTypes)),
		Unit:     telemetry.UnitCount,
	})

	return samples, nil
}
