package collectors

import (
	"context"

	"github.com/go-logr/logr"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/consts"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

var (
	loadBalancerInfo = prometheus.NewDesc(
		"dataplane_manager_loadbalancer_info",
		"Information about loadBalancer CR.",
		[]string{
			"name",
			"tenant_id",
			"status",
		}, nil)
	publicLoadBalancerDNSReachable = prometheus.NewDesc(
		"dataplane_manager_public_loadbalancer_dns_reachable",
		"Latest public DNS reachability probe result for public LoadBalancer CR.",
		[]string{
			"name",
			"namespace",
			"tenant_id",
			"cluster_id",
			"tidb_group_id",
			"dns",
			"reason",
		}, nil)
)

type loadBalancer struct {
	cli client.Client
	log logr.Logger
}

var _ prometheus.Collector = &loadBalancer{}

func (l *loadBalancer) Describe(ch chan<- *prometheus.Desc) {
	ch <- loadBalancerInfo
	ch <- publicLoadBalancerDNSReachable
}

func (l *loadBalancer) Collect(ch chan<- prometheus.Metric) {
	loadBalancerList := &v1alpha1.LoadBalancerList{}
	if err := l.cli.List(context.Background(), loadBalancerList); err != nil {
		l.log.Error(err, "fetching loadBalancerList")
		return
	}
	for _, lbCR := range loadBalancerList.Items {
		tenant := lbCR.GetLabels()[consts.TenantLabelKey]

		ch <- prometheus.MustNewConstMetric(
			loadBalancerInfo,
			prometheus.GaugeValue,
			1,
			lbCR.Name,
			tenant,
			string(lbCR.Status.Phase),
		)
		l.collectPublicDNSReachability(ch, &lbCR)
	}
}

func (l *loadBalancer) collectPublicDNSReachability(ch chan<- prometheus.Metric, lbCR *v1alpha1.LoadBalancer) {
	if lbCR.Spec.Type != v1alpha1.PublicLoadBalancerType {
		return
	}
	if lbCR.Status.DNS == "" {
		return
	}
	annotations := lbCR.GetAnnotations()
	reachable, ok := annotations[consts.AnnotationKeyPublicDNSReachable]
	if !ok {
		return
	}

	value := 0.0
	if reachable == "true" {
		value = 1.0
	}

	labels := lbCR.GetLabels()
	ch <- prometheus.MustNewConstMetric(
		publicLoadBalancerDNSReachable,
		prometheus.GaugeValue,
		value,
		lbCR.Name,
		lbCR.Namespace,
		labels[consts.TenantLabelKey],
		labels[consts.ClusterLabelKey],
		labels[consts.TiDBGroupLabelKey],
		lbCR.Status.DNS,
		annotations[consts.AnnotationKeyPublicDNSReason],
	)
}
