package service

import (
	"context"
	"errors"
	"fmt"
	"testing"
	"time"

	"github.com/prometheus/client_golang/prometheus/testutil"

	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/metrics"
)

func TestCronJobMetrics(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name   string
		result string
		do     CronJobDo
	}{
		{
			name:   "success",
			result: "success",
			do:     func(ctx context.Context) error { return nil },
		},
		{
			name:   "failed",
			result: "failed",
			do:     func(ctx context.Context) error { return errors.New("failed") },
		},
		{
			name:   "retriable",
			result: "retriable",
			do:     func(ctx context.Context) error { return RetriableErrorf("retry") },
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()
			runCronJobMetricTest(t, tt.result, tt.do)
		})
	}
}

func runCronJobMetricTest(t *testing.T, result string, do CronJobDo) {
	t.Helper()
	registerTestServiceMetrics()

	serviceName := "CronJobMetricService"
	jobName := fmt.Sprintf("cron-metric-%s-%d", result, time.Now().UnixNano())
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	ctx = context.WithValue(ctx, serviceNameContextKey{}, serviceName)

	beforeCount := testutil.ToFloat64(
		metrics.ServiceCronJob.SyncCount.WithLabelValues(serviceName, jobName, result),
	)
	beforeDurCount := summarySampleCount(t, metrics.ServiceCronJob.SyncDur, serviceName, jobName, result)

	job := NewConstantCronJob(jobName, time.Hour, do, WithInitDelay(time.Millisecond))
	go job.Run(ctx)

	eventually(t, time.Second, 20*time.Millisecond, func() bool {
		return testutil.ToFloat64(
			metrics.ServiceCronJob.SyncCount.WithLabelValues(serviceName, jobName, result),
		) == beforeCount+1
	}, "cron job sync count was not incremented")
	eventually(t, time.Second, 20*time.Millisecond, func() bool {
		return summarySampleCount(t, metrics.ServiceCronJob.SyncDur, serviceName, jobName, result) == beforeDurCount+1
	}, "cron job sync duration count was not incremented")
}
