package tidbmanager

import (
	"context"
	"fmt"
	"time"

	perrors "github.com/pingcap/errors"
	"github.com/tidbcloud/aws-shared-provider/pkg/utils"
	ep "github.com/tidbcloud/aws-shared-provider/pkg/utils/endpoint"
	"github.com/tidbcloud/aws-shared-provider/pkg/utils/kubeapi"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
	checkTidbStatusTimeout = 2 * time.Second
)

var (
	tidbStatusPort = 10080
)

func (t *tidbManager) CheckTidb(ctx context.Context, token, podIP string) error {
	tInfo, ok := t.assignCache.getTidbInfo(token)
	if !ok {
		return perrors.Annotatef(utils.ErrNotFoundToken, "failed to CheckTidb for token %s, ip %s", token, podIP)
	}
	checkLog := t.WithName("CheckTidb").WithValues("token", token, "inputIP", podIP)

	for _, endpoint := range tInfo.endpoints {
		name, ip := ep.ParsePodFromEndpoint(endpoint)
		checkLog.Info("start to check endpoint", "targetPodName", name, "targetPodIP", ip)
		if err := func() error {
			pod := &corev1.Pod{}
			if err := t.client.Get(ctx, client.ObjectKey{Name: name, Namespace: t.tidbPoolNamespace}, pod); err != nil {
				if apierrors.IsNotFound(err) {
					checkLog.Info("not found in k8s, remove endpoint now", "targetPodName", name, "targetPodIP", ip)
					return t.removeEndpointByToken(ctx, token, endpoint, "check tidb, not found in k8s")
				}
				return err
			}

			if pod.GetDeletionTimestamp() != nil {
				checkLog.Info("pod is terminating, skip", "targetPodName", name, "targetPodIP", ip)
				return nil
			}

			if !kubeapi.IsPodReady(pod) {
				checkLog.Info("pod is not ready, remove now", "targetPodName", name, "targetPodIP", ip)
				t.removePod(removePod{name: name})
				return nil
			}

			checkCtx, cancel := context.WithTimeout(ctx, checkTidbStatusTimeout)
			tidbStatus, err := t.tidbController.GetStatus(checkCtx, fmt.Sprintf("%s:%d", ip, tidbStatusPort))
			cancel()
			if err != nil {
				checkLog.Error(err, "get tidb status error", "targetPodName", name, "targetPodIP", ip)
				return err
			}
			if tidbStatus.KeyspaceName != utils.TrimToken(token) {
				checkLog.Info("tidb is activated by other token, remove endpoint now", "targetPodName", name, "targetPodIP", ip)
				return t.removeEndpointByToken(ctx, token, endpoint, "check tidb, activated by other token")
			}
			if !tidbStatus.IsActivated() {
				checkLog.Info("tidb is not activated, remove endpoint now", "targetPodName", name, "targetPodIP", ip)
				return t.removeEndpointByToken(ctx, token, endpoint, "check tidb, not activated")
			}

			return nil
		}(); err != nil {
			checkLog.Error(err, "failed to check endpoint", "targetPodName", name, "targetPodIP", ip)
		}
	}

	checkLog.Info("all endpoints has been checked")
	return nil
}
