package tidbupgrader

import (
	"errors"

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

const (
	minOldRevPercent = 0.1
)

func (tu *TidbUpgrader) handleFreeCache() error {
	tidbPool := tu.tidbPool
	tu.oldPodInFreeCache = tu.tManager.GetOldTidbFromFreeCache(tidbPool.Revision, true)
	tu.freeCacheSize = tu.tManager.FreeCacheSize()
	oldPodInFreeCacheSize := len(tu.oldPodInFreeCache)
	metrics.OldPodFreeCacheSizeGauge.WithLabelValues(tidbPool.Revision, tu.tidbPoolNamespace).
		Set(float64(oldPodInFreeCacheSize))
	metrics.FreeCacheSizeGauge.WithLabelValues(tidbPool.Revision, tu.tidbPoolNamespace).
		Set(float64(tu.freeCacheSize))
	if oldPodInFreeCacheSize == 0 {
		return nil
	}

	abnormalList, err := tu.pool.GetAbnormalPodList(tu.ctx)
	if err != nil {
		tu.Error(err, "get abnormal tidb pod list")
		return err
	}
	maxAbnormalPods := 2 * tu.tidbPool.MinSize
	if maxAbnormalPods == 0 {
		maxAbnormalPods = types.MaxAbnormalTidbPods
	}
	if len(abnormalList) > maxAbnormalPods {
		tu.Info("abnormal tidb pods too much, skip createNewPod", "count", len(abnormalList), "max", maxAbnormalPods)
		return errors.New("abnormal tidb pods too much")
	}

	tu.expandNewRevisionToMinSize()
	tu.shrinkOldRevisionToMaxSize()

	return nil
}

func (tu *TidbUpgrader) expandNewRevisionToMinSize() {
	newRevisionPods := tu.tManager.GetTidbFromFreeCacheByRevision(tu.tidbPool.Revision, true)
	if len(newRevisionPods) >= tu.tidbPool.MinSize {
		return
	}

	addSize := tu.tidbPool.MinSize - len(newRevisionPods)
	tu.Info("expand new revision pods to min size", "new revision pods", len(newRevisionPods), "min size", tu.tidbPool.MinSize, "add size", addSize)
	for i := 0; i < addSize; i++ {
		if err := tu.tManager.TryCreatePod(tu.ctx); err != nil {
			tu.Error(err, "create tidb pod")
		}
	}
}

func (tu *TidbUpgrader) shrinkOldRevisionToMaxSize() {
	oldRevisionPods := tu.tManager.GetOldTidbFromFreeCache(tu.tidbPool.Revision, true)
	if len(oldRevisionPods) <= tu.tidbPool.MaxSize {
		return
	}

	removeSize := len(oldRevisionPods) - tu.tidbPool.MaxSize
	tu.Info("shrink old revision pods to max size", "old revision pods", len(oldRevisionPods), "max size", tu.tidbPool.MaxSize, "remove size", removeSize)
	for i := 0; i < removeSize; i++ {
		if err := tu.deleteOldPodInFreeCache(oldRevisionPods[i]); err != nil {
			tu.Error(err, "delete tidb pod in free cache", "pod name", oldRevisionPods[i])
		}
	}
}

func (tu *TidbUpgrader) deleteOldPodInFreeCache(podName string) error {
	removePod := &corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      podName,
			Namespace: tu.pool.Namespace(),
		},
	}
	err := tu.client.Delete(tu.ctx, removePod, &client.DeleteOptions{GracePeriodSeconds: ptr.To[int64](0)})
	if err == nil {
		tu.Info("[pod lifecycle] delete tidb pod in free cache", "pod name", podName)
	}

	return client.IgnoreNotFound(err)
}
