// Package opworker is the background worker of the central service.
// The central service records intent to make changes.
// The worker finds those in the database, performs them, and updates the database.
package opworker

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/tidbcloud/account/commons/metrics"

	"github.com/tidbcloud/account/internel/dao/entity"
	"github.com/tidbcloud/pkgv2/worker"
)

func (w *BgWorker) Start() {
	for _, item := range w.workers {
		item.Start()
	}
}

func (w *BgWorker) Stop() {
	wg := sync.WaitGroup{}
	wg.Add(len(w.workers))
	for _, item := range w.workers {
		go func(wi *worker.PeriodWorker) {
			defer wg.Done()
			wi.Stop()
		}(item)
	}
	wg.Wait()
}

// NewBgWorker creates a new worker.
func NewBgWorker(tenantID entity.ID) (*BgWorker, error) {
	bgWorker := &BgWorker{
		tenantID: tenantID,
	}
	bgWorker.workers = []*worker.PeriodWorker{}
	return bgWorker, nil
}

// BgWorker is a base worker used by other workers
// Using it in WorkLoop() will build the other workers
type BgWorker struct {
	tenantID entity.ID

	workers []*worker.PeriodWorker
}

func withMetrics(tenantID uint64, workerName string, f worker.Handler) worker.Handler {
	return func(ctx context.Context) error {
		tBegin := time.Now()
		status := metrics.LoopOK
		err := f(ctx)
		if err != nil {
			status = metrics.LoopError
		}
		duration := float64(time.Since(tBegin)) / float64(time.Millisecond)
		metrics.WorkerDuration.WithLabelValues(fmt.Sprintf("%d", tenantID), workerName, status).Observe(duration)
		return err
	}
}
