package tidbmanager

import (
	"context"
	"runtime/debug"
	"strings"
	"time"

	"github.com/pingcap/errors"
)

func (t *tidbManager) TryCreatePod(ctx context.Context) error {
	pool := t.tidbPool.GetPool(ctx)
	newFreeCacheSize := len(t.GetTidbFromFreeCacheByRevision(pool.Revision, false))
	creatingSize := t.creatingPodsCount(pool.Revision)
	t.Info(
		"try create pod",
		"newFreeCacheSize", newFreeCacheSize,
		"creatingSize", creatingSize,
		"poolMinSize", pool.MinSize,
		"poolMaxSize", pool.MaxSize,
		"revision", pool.Revision,
	)
	minSize, maxSize := pool.MinSize, pool.MaxSize
	if minSize == 0 {
		// make sure when pool minSize = 0, assign cache can rollout normally
		minSize = 1
	}
	if maxSize == 0 {
		// make sure when pool maxSize = 0, assign cache can rollout normally
		maxSize = 1
	}

	if creatingSize >= minSize {
		err := errors.New("creating pods exceed min size, skip create pod")
		t.Info(err.Error(), "creatingSize", creatingSize, "minSize", minSize, "poolMinSize", pool.MinSize)
		return err
	}
	if newFreeCacheSize+creatingSize >= maxSize {
		err := errors.New("current revision free cache plus creating pods exceed max size, skip create pod")
		t.Info(err.Error(), "newFreeCacheSize", newFreeCacheSize, "creatingSize", creatingSize, "maxSize", maxSize, "poolMaxSize", pool.MaxSize)
		return err
	}

	pod := pool.TidbPod.DeepCopy()
	if err := t.client.Create(ctx, pod); err != nil {
		t.Error(err, "create tidb pod failed", "pod_name", pod.Name)
		return err
	}
	t.addCreatingPod(pod.Name)
	t.Info("[pod lifecycle] create tidb pod", "pod_name", pod.Name, "stack", string(debug.Stack()))
	return nil
}

func (t *tidbManager) addCreatingPod(podName string) {
	t.creatingPods.Store(podName, time.Now())
}

func (t *tidbManager) deleteCreatingPod(podName string) {
	t.creatingPods.Delete(podName)
}

func (t *tidbManager) creatingPodsCount(pattern string) int {
	count := 0
	t.creatingPods.Range(func(key, value any) bool {
		if len(pattern) > 0 {
			keyStr := key.(string)
			if strings.Contains(keyStr, pattern) {
				count++
			}
		} else {
			count++
		}
		return true
	})
	return count
}
