package service

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

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	"github.com/tidbcloud/devops/pkg/infra/errs"
	metrics "github.com/tidbcloud/devops/pkg/infra/metrics/devops-server"

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

var _ = Describe("CronJob metrics", func() {
	runOne := func(result string, do CronJobDo) {
		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.CronJob.SyncCount.WithLabelValues(serviceName, jobName, result),
		)
		beforeDurCount := summarySampleCount(metrics.CronJob.SyncDur, serviceName, jobName, result)

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

		Eventually(func() float64 {
			return testutil.ToFloat64(
				metrics.CronJob.SyncCount.WithLabelValues(serviceName, jobName, result),
			)
		}, time.Second, 20*time.Millisecond).Should(Equal(beforeCount + 1))
		Eventually(func() uint64 {
			return summarySampleCount(metrics.CronJob.SyncDur, serviceName, jobName, result)
		}, time.Second, 20*time.Millisecond).Should(Equal(beforeDurCount + 1))
	}

	It("should emit metrics for success result", func() {
		runOne("success", func(ctx context.Context) error { return nil })
	})

	It("should emit metrics for failed result", func() {
		runOne("failed", func(ctx context.Context) error { return errors.New("failed") })
	})

	It("should emit metrics for retriable result", func() {
		runOne("retriable", func(ctx context.Context) error { return errs.RetriableErrorf("retry") })
	})
})
