package gc

import (
	"context"
	"time"

	"github.com/go-logr/logr"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type GC struct {
	conf      config.GCConfig
	log       logr.Logger
	resources []gcWorker
}

func NewGC(conf config.GCConfig, cli client.Client, log logr.Logger) *GC {
	return &GC{
		conf: conf,
		log:  log,
		resources: []gcWorker{
			NewappBoxGCWorker(cli, log.WithName("appbox-gcworker"), conf),
			NewInternetGCWorker(cli, log.WithName("internet-gcworker"), conf),
		},
	}
}

func (g *GC) Run(ctx context.Context) error {
	timer := time.NewTicker(g.conf.CheckIdleInterval.Duration)
	g.log.Info("GC worker started", "gc config", g.conf)
	defer func() {
		timer.Stop()
		g.log.Info("GC worker stopped")
	}()
	for {
		select {
		case <-ctx.Done():
			return nil
		case <-timer.C:
		}
		g.log.Info("GC worker check idle resources")
		if err := g.scanIdleResources(ctx); err != nil {
			g.log.Error(err, "check idle resources failed, retry later")
			continue
		}
		g.log.Info("GC worker clean idle resources")
		if err := g.cleanIdleResources(context.Background()); err != nil {
			g.log.Error(err, "clean idle resources failed, retry later")
			continue
		}
	}
}

func (g *GC) scanIdleResources(ctx context.Context) error {
	for _, resource := range g.resources {
		if err := resource.scanIdle(ctx); err != nil {
			return err
		}
	}
	return nil
}

func (g *GC) cleanIdleResources(ctx context.Context) error {
	for _, resource := range g.resources {
		if err := resource.cleanIdle(ctx); err != nil {
			return err
		}
	}
	return nil
}

type gcWorker interface {
	scanIdle(ctx context.Context) error
	cleanIdle(ctx context.Context) error
}
