package metrics

import (
	"context"
	"fmt"
	"lunar/toolkit-core/haproxy"

	"github.com/rs/zerolog/log"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/metric"
)

const haproxySocketPath = "/var/run/haproxy/haproxy.sock"

type remainingConnectionsMetricManager struct {
	haproxy    *haproxy.Stats
	observer   metric.Int64ObservableGauge
	attributes []attribute.KeyValue
}

func newRemainingConnectionsMetricManager(
	meter metric.Meter,
) (*remainingConnectionsMetricManager, error) {
	mng := &remainingConnectionsMetricManager{
		attributes: []attribute.KeyValue{},
	}

	if err := mng.init(meter); err != nil {
		return nil, fmt.Errorf("failed to initialize remaining connections metric manager: %w", err)
	}

	log.Debug().Msg("Remaining connections metric manager created successfully")
	return mng, nil
}

func (m *remainingConnectionsMetricManager) remainingConnectionsCallback(
	_ context.Context,
	observer metric.Int64Observer,
) error {
	remainingConns, err := m.haproxy.QueryRemainingConnections()
	if err != nil {
		return err
	}

	observer.Observe(
		int64(remainingConns),
		metric.WithAttributes(m.attributes...),
	)

	return nil
}

func (m *remainingConnectionsMetricManager) init(meter metric.Meter) error {
	haproxyClient, err := haproxy.NewHAProxyStatsClient(haproxySocketPath)
	if err != nil {
		return fmt.Errorf("failed to create HAProxy stats client: %w", err)
	}

	m.haproxy = haproxyClient
	m.attributes = appendGatewayIDAttribute(m.attributes...)
	m.observer, err = meter.Int64ObservableGauge(
		MetricPrefix+string(RemainingConnectionsMetric),
		metric.WithDescription("The number of remaining connections in the pool"),
		metric.WithInt64Callback(m.remainingConnectionsCallback),
	)
	if err != nil {
		return err
	}

	log.Debug().Msg("Remaining connections metric manager initialized successfully")
	return nil
}
