package tidbmanager

import (
	"runtime/debug"
	"strconv"

	"github.com/tidbcloud/aws-shared-provider/pkg/metrics"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/utils/ptr"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type removePod struct {
	name  string
	force bool
	f     func()
}

func (t *tidbManager) processRemovePod(workerCount int) {
	for workerCount > 0 {
		go t.worker()
		workerCount--
	}
}

func (t *tidbManager) worker() {
	for {
		select {
		case rp := <-t.removePodQueue:
			metrics.RemovePodCounter.WithLabelValues(t.tidbPoolNamespace).Inc()
			t.V(2).Info("in removePodQueue worker", "pod name", rp.name)

			po := &corev1.Pod{}
			err := t.client.Get(t.ctx, client.ObjectKey{Name: rp.name, Namespace: t.tidbPoolNamespace}, po)
			if apierrors.IsNotFound(err) || (err == nil && po.DeletionTimestamp != nil) {
				if rp.f != nil {
					rp.f()
				}
				continue
			}
			if err != nil {
				// requeue if err
				t.Error(err, "Get pod", "pod name", rp.name)
				t.removePod(rp) // should avoid chan deadlock
				continue
			}

			deleteOptions := &client.DeleteOptions{}
			if rp.force {
				deleteOptions.GracePeriodSeconds = ptr.To[int64](0)
			}
			if err := t.client.Delete(t.ctx, po, deleteOptions); client.IgnoreNotFound(err) != nil {
				// requeue if err
				t.Error(err, "Delete pod", "pod name", rp.name)
				t.removePod(rp) // should avoid chan deadlock
				continue
			}

			if rp.f != nil {
				rp.f()
			}
			t.Info("[pod lifecycle] remove pod success", "pod name", rp.name)
		case <-t.ctx.Done():
			return
		}
	}
}

// TODO: we should use real queue, in order to cache lots of events and retry, backoff
func (t *tidbManager) removePod(rp removePod) bool {
	select {
	case t.removePodQueue <- rp:
		metrics.RemovePodQueueLenGauge.WithLabelValues(strconv.Itoa(cap(t.removePodQueue)), t.tidbPoolNamespace).
			Set(float64(len(t.removePodQueue)))
		t.Info("[pod lifecycle] receive removePod request", "pod name", rp.name, "force", rp.force, "stack", string(debug.Stack()))
		return true
	default:
		metrics.RemovePodQueueOverflowCounter.WithLabelValues(t.tidbPoolNamespace).Inc()
		t.Info("[pod lifecycle] removePodQueue full", "pod name", rp.name, "force", rp.force,
			"size", len(t.removePodQueue), "cap", cap(t.removePodQueue), "stack", string(debug.Stack()))
	}

	return false
}
