// Package worker add by blacknc <blacknc@163.com> at 2023/09/22 11:04:30
package worker

import (
	"context"
	"dataservices/commons/utils"
	"sync"
	"sync/atomic"
	"time"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/trace"
)

type Worker interface {
	Name() string
	Handle(trace.Tracer)
	IsEnable() bool
	RunningMsInterval() time.Duration
}

type WorkerManager struct {
	inShutdown atomic.Bool
	tracer     trace.Tracer
	wg         sync.WaitGroup
	workers    []Worker
}

func NewWorkerManager(workers ...Worker) *WorkerManager {
	var wm WorkerManager
	wm.tracer = otel.GetTracerProvider().Tracer("dataservice-central-worker")
	wm.workers = workers
	return &wm
}

func (wm *WorkerManager) shuttingDown() bool {
	return wm.inShutdown.Load()
}

func (wm *WorkerManager) Shutdown(ctx context.Context) {
	wm.inShutdown.Store(true)

	waitShutdown := make(chan struct{}, 1)
	utils.GO(func() {
		wm.wg.Wait()
		waitShutdown <- struct{}{}
	})

	select {
	case <-waitShutdown:
	case <-ctx.Done():
	}
}

func (wm *WorkerManager) Process() {
	for i := range wm.workers {
		wm.wg.Add(1)
		worker := wm.workers[i]
		workerName := worker.Name()
		utils.GOWithName(workerName, func() {
			if !worker.IsEnable() {
				return
			}
			defer wm.wg.Done()
			for {
				if wm.shuttingDown() {
					return
				}
				worker.Handle(wm.tracer)
				time.Sleep(worker.RunningMsInterval())
			}
		})
	}
}
