package gc

import (
	"context"
	"time"

	"github.com/pingcap/log"
	"github.com/tidbcloud/ticdc-service/pkg/cloud"
	"github.com/tidbcloud/ticdc-service/pkg/config"
	"github.com/tidbcloud/ticdc-service/pkg/regionalservice"
	"go.uber.org/zap"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type GC struct {
	conf   *config.Config
	worker Worker
}

func NewGC(conf *config.Config,
	cli client.Client) *GC {
	regionalCli := regionalservice.NewRegionalServiceClient(conf.RegionalServiceBaseURL)
	var (
		appBoxLister cloud.AppboxLister
		gcExecutor   cloud.GCExecutor
	)

	switch p := conf.Provider; p {
	case config.ProviderAWS:
		appBoxLister = cloud.NewAwsGCProvider(cli)
		gcExecutor = cloud.NewAwsGCProvider(cli)
	case config.ProviderAzure:
		appBoxLister = cloud.NewAzureGCProvider(cli)
		gcExecutor = cloud.NewAzureGCProvider(cli)
	case config.ProviderGCP:
		appBoxLister = cloud.NewGcpGCProvider(cli)
		gcExecutor = cloud.NewGcpGCProvider(cli)
	default:
		panic("unimplemented")
	}
	return &GC{
		conf:   conf,
		worker: NewDataPlaneGCWorker(regionalCli, gcExecutor, appBoxLister),
	}
}

func (g *GC) Run(ctx context.Context) error {
	timer := time.NewTicker(time.Duration(g.conf.GCConfig.CheckIntervalInSecond) * time.Second)
	log.Info("GC worker started", zap.Any("config", g.conf.GCConfig))
	defer func() {
		timer.Stop()
		log.Info("GC worker stopped")
	}()
	for {
		select {
		case <-ctx.Done():
			return nil
		case <-timer.C:
		}
		log.Info("GC worker gc resources")
		if err := g.worker.Run(ctx); err != nil {
			log.Error("gc resources failed, retry later", zap.Error(err))
		}
	}
}

type Worker interface {
	Run(ctx context.Context) error
}
