package etcd

import (
	"context"
	"fmt"
	"strings"

	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
	dataplaneAdminNamespace       = "tidb-admin"
	dataplaneKongProxyServiceName = "clustergateway-kong-proxy"
)

func GetDataplaneKongLBHostname(ctx context.Context, remoteCli client.Client) (string, error) {
	service := &corev1.Service{}

	if err := remoteCli.Get(ctx, client.ObjectKey{Namespace: dataplaneAdminNamespace, Name: dataplaneKongProxyServiceName}, service); err != nil {
		return "", fmt.Errorf("get kong %s service : %w", dataplaneKongProxyServiceName, err)
	}
	if count := len(service.Status.LoadBalancer.Ingress); count != 1 {
		return "", fmt.Errorf("unexpected kong %s ingress length: %d", dataplaneKongProxyServiceName, count)
	}

	address := service.Status.LoadBalancer.Ingress[0].Hostname
	if address == "" {
		address = service.Status.LoadBalancer.Ingress[0].IP
	}
	return address, nil
}

func GetTiDBGroupGatewayUrl(clusterGatewayUrl, sharedPoolId, groupId string) string {
	if clusterGatewayUrl == "" {
		return ""
	}

	if !strings.HasPrefix(clusterGatewayUrl, "http") {
		clusterGatewayUrl = fmt.Sprintf("http://%s", clusterGatewayUrl)
	}

	return fmt.Sprintf("%s/dataplane/proxy/cluster/%s/group/%s", clusterGatewayUrl, sharedPoolId, groupId)
}

func GetEndpointService(ctx context.Context, remoteCli client.Client, namespace, svcName string) (*corev1.Service, error) {
	service := &corev1.Service{}

	if err := remoteCli.Get(ctx, client.ObjectKey{Namespace: namespace, Name: svcName}, service); err != nil {
		return nil, err
	}

	return service, nil
}

func FullTidbGroup(ctx context.Context, tidbGroup *entity.TiDBGroup, tidbComp, tiproxyComp *entity.Component) {
	if tidbGroup == nil {
		return
	}

	tidbGroup.Version = tidbComp.GetVersion()

	tidbGroup.Phase = cvtToTidbGroupStatus(tidbComp.GetPhase())

	tidbGroup.NodeQuota = tidbComp.GetNodeQuota()

	if tidbGroup.GetPhase() != apiv1.TiDBGroup_AVAILABLE {
		return
	}

	if tiproxyComp == nil {
		return
	}

	// also check tiproxy component phase
	if tiproxyComp.GetPhase() != apiv1.Component_AVAILABLE {
		tidbGroup.Phase = cvtToTidbGroupStatus(tiproxyComp.GetPhase())
	}
}

func cvtToTidbGroupStatus(compStatus apiv1.Component_Phase) entity.TiDBGroupPhase {
	var tgStatus entity.TiDBGroupPhase
	switch compStatus {
	case apiv1.Component_AVAILABLE:
		tgStatus = apiv1.TiDBGroup_AVAILABLE
	case apiv1.Component_MODIFYING:
		tgStatus = apiv1.TiDBGroup_MODIFYING
	case apiv1.Component_CREATING:
		tgStatus = apiv1.TiDBGroup_CREATING
	default:
		tgStatus = apiv1.TiDBGroup_UNAVAILABLE
	}
	return tgStatus
}
