package slprober

import (
	"context"
	"fmt"
	"time"

	"github.com/pingcap/log"
	"go.uber.org/zap"

	v1 "k8s.io/api/core/v1"

	"github.com/tidbcloud/sli-reporter/slprober/handshake"
)

type tidbGroupResult struct {
	success       bool
	tidbGroupName string
}

func probeNextGenSvc(
	ctx context.Context,
	clusterID string,
	groupName string,
	groupType string,
	svc *v1.Service,
	resultCh chan<- tidbGroupResult,
	handshakeCli handshake.Interface,
) {
	timeBegin := time.Now()
	logger := log.L().With(zap.String("clusterID", clusterID),
		zap.String("groupType", groupType),
		zap.String("groupName", groupName))
	logger.Info("begin probe next gen svc")

	probeServiceCount := 1
	serviceResultCh := make(chan serviceResult, probeServiceCount)
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	go probeTiDBService(ctx,
		fmt.Sprintf("%s:%d", svc.Spec.ClusterIP, getPort(svc)),
		svc.Name,
		serviceResultCh,
		handshakeCli,
	)

	resultCount := 0
	for {
		select {
		case <-ctx.Done():
			logger.Info("finish probe next gen svc, context done",
				zap.String("elapsed", time.Since(timeBegin).String()),
			)
			return
		case result := <-serviceResultCh:
			resultCount++
			if !result.success {
				// once we get a dead result, we can cancel the other goroutines
				logger.Info("finish probe next gen svc, detected as dead",
					zap.String("elapsed", time.Since(timeBegin).String()),
				)
				resultCh <- tidbGroupResult{
					success:       false,
					tidbGroupName: groupName,
				}
				return
			}
			if resultCount >= probeServiceCount {
				// all services are alive
				logger.Info("finish probe next gen svc, detected as alive",
					zap.String("elapsed", time.Since(timeBegin).String()),
				)
				resultCh <- tidbGroupResult{
					success:       true,
					tidbGroupName: groupName,
				}
				return
			}
		}
	}
}

func getPort(service *v1.Service) int {
	return getTiDBServicePort(service)
}
