package resourcepoolcpulimit

import (
	"context"
	"time"

	"github.com/prometheus/client_golang/prometheus"

	"github.com/tidbcloud/cluster-service-ng/internal/dataplane-exporter/pkg/diagnostics"
)

type Reader interface {
	Read(ctx context.Context) (Snapshot, error)
}

type Exporter struct {
	reader Reader
}

func NewExporter(reader Reader) *Exporter {
	return &Exporter{reader: reader}
}

func (e *Exporter) Name() string {
	return "resource-pool-cpu-limit"
}

func (e *Exporter) Register(ctx context.Context, reg prometheus.Registerer) {
	reg.MustRegister(newCollector(ctx, e.reader))
}

type collector struct {
	ctx          context.Context
	reader       Reader
	mainDesc     *prometheus.Desc
	successDesc  *prometheus.Desc
	durationDesc *prometheus.Desc
}

func newCollector(ctx context.Context, reader Reader) *collector {
	return &collector{
		ctx:    ctx,
		reader: reader,
		mainDesc: prometheus.NewDesc(
			diagnostics.MetricResourcePoolCPULimit,
			"Resource pool CPU limit from the shared pool vCPU ceiling resource quota.",
			[]string{"tenant", "resource_pool", "namespace"},
			nil,
		),
		successDesc: prometheus.NewDesc(
			diagnostics.MetricResourcePoolCPULimitSuccess,
			"Whether the resource pool CPU limit scrape succeeded.",
			nil,
			nil,
		),
		durationDesc: prometheus.NewDesc(
			diagnostics.MetricResourcePoolCPULimitDuration,
			"Duration of the resource pool CPU limit scrape in seconds.",
			nil,
			nil,
		),
	}
}

func (c *collector) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.mainDesc
	ch <- c.successDesc
	ch <- c.durationDesc
}

func (c *collector) Collect(ch chan<- prometheus.Metric) {
	started := time.Now()
	snapshot, err := c.reader.Read(c.ctx)
	success := 1.0
	if err != nil {
		success = 0
	} else {
		for _, sample := range snapshot.Samples {
			ch <- prometheus.MustNewConstMetric(
				c.mainDesc,
				prometheus.GaugeValue,
				sample.CPULimit,
				sample.Tenant,
				sample.ResourcePool,
				sample.Namespace,
			)
		}
	}

	ch <- prometheus.MustNewConstMetric(c.successDesc, prometheus.GaugeValue, success)
	ch <- prometheus.MustNewConstMetric(c.durationDesc, prometheus.GaugeValue, time.Since(started).Seconds())
}
