package tidbmanager

import (
	"context"
	"os"
	"strings"
	"time"

	providertypes "github.com/tidbcloud/aws-shared-provider/pkg/types"
	ep "github.com/tidbcloud/aws-shared-provider/pkg/utils/endpoint"
)

const connectionIdleDelayEnv = "CONNECTION_IDLE_DELAY"

func (t *tidbManager) removeTokenHandler(token string, modRevision int64) {
	if pre, ok := t.assignCache.removeToken(token); ok {
		if t.IsLeader() {
			for _, endpoint := range pre.endpoints {
				podName, _ := ep.ParsePodFromEndpoint(endpoint)
				t.removePod(removePod{name: podName})
			}
		}
		t.notifier.Send(token, &ep.Endpoints{
			TidbPool:    t.tidbPoolNamespace,
			Comment:     "remove token",
			ModRevision: modRevision,
		})
	}
}

func (t *tidbManager) endpointsHandler(token, endpoints string, modRevision int64) {
	t.standbyCheckMu.Lock()
	pre := t.assignCache.setTidbInfoEndpoints(token, endpoints, modRevision)
	now := newTidbInfo(endpoints, 0, modRevision)
	inc, dec := now.diffEndpoint(pre)
	for _, endpoint := range inc {
		podName, podIP := ep.ParsePodFromEndpoint(endpoint)
		t.V(3).Info("watch endpoints change: remove from freeCache",
			"token", token, "pod name", podName)
		t.freeCache.removePodIfIP(podName, podIP)
	}
	t.standbyCheckMu.Unlock()

	if len(inc) > 0 && t.IsLeader() && t.tidbScaler != nil {
		t.tidbScaler.TryScale()
	}
	if now.comment != providertypes.CommentSkipSetToFreeCache {
		for _, endpoint := range dec {
			podName, _ := ep.ParsePodFromEndpoint(endpoint)
			t.V(3).Info("watch endpoints change: maybe try remove to freeCache",
				"token", token, "pod name", podName)
			t.checkAndSetToFreeCacheFromEndpointsHandler(t.ctx, podName, now.comment)
		}
	}

	t.notifier.Send(token, &ep.Endpoints{
		Endpoints:   now.endpoints,
		TidbPool:    t.tidbPoolNamespace,
		Comment:     now.comment,
		ModRevision: max(modRevision, pre.replicasModRevision),
		Replicas:    pre.replicas,
	})
}

func (t *tidbManager) removeReplicasHandler(token string) {
	if pre, ok := t.assignCache.removeToken(token); ok && len(pre.endpoints) > 0 && t.IsLeader() {
		for _, endpoint := range pre.endpoints {
			podName, _ := ep.ParsePodFromEndpoint(endpoint)
			t.removePod(removePod{name: podName})
		}
	}
}

func (t *tidbManager) replicasHandler(token string, replicas int, modRevision int64) {
	if pre, exist := t.assignCache.modifyTidbInfoReplicas(token, replicas, modRevision); exist {
		t.notifier.Send(token, &ep.Endpoints{
			Endpoints:   pre.endpoints,
			TidbPool:    t.tidbPoolNamespace,
			Comment:     pre.comment,
			ModRevision: max(pre.endpointsModRevision, modRevision),
			Replicas:    replicas,
		})
	}
}

func (t *tidbManager) checkAndSetToFreeCacheFromEndpointsHandler(ctx context.Context, podName, comment string) {
	delay := t.checkConnectionIdleDelay()
	if delay <= 0 {
		t.checkAndSetToFreeCache(ctx, podName)
		return
	}

	if comment == providertypes.CommentConnectionIdle {
		time.AfterFunc(delay, func() { t.checkAndSetToFreeCache(ctx, podName) })
	}
}

func (t *tidbManager) checkConnectionIdleDelay() time.Duration {
	rawDelay := strings.TrimSpace(os.Getenv(connectionIdleDelayEnv))
	if rawDelay == "" {
		return 0
	}

	delay, err := time.ParseDuration(rawDelay)
	if err != nil {
		t.Error(err, "ignore invalid connectionIdleDelayEnv", "env", connectionIdleDelayEnv, "value", rawDelay)
		return 0
	}
	if delay <= 0 {
		t.Info("ignore non-positive connectionIdleDelayEnv", "env", connectionIdleDelayEnv, "value", rawDelay)
		return 0
	}

	return delay
}
