package metrics

import (
	"strings"
	"testing"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/testutil"
	"github.com/stretchr/testify/require"
)

func TestDaemonTransportMetricsRecordLowCardinalityLabels(t *testing.T) {
	reg := prometheus.NewRegistry()
	transport, err := RegisterDaemonTransport(reg)
	require.NoError(t, err)

	transport.RecordRemoteRequest("workspace.list", "elastic_request_link", "success", "none", 25*time.Millisecond)
	transport.RecordRouteDecision("workspace.list", "elastic_preferred", "open_elastic_request_link", "open_elastic_request_link")
	transport.RecordElasticEvent("link_rejected", "node_mismatch")
	transport.RecordWarmEvent("user_interactive", "user_interactive_read_review_v1", "lease_refreshed", "web_api")
	transport.SetElasticPool("links", 2)

	require.Equal(t, float64(1), testutil.ToFloat64(transport.requests.WithLabelValues("workspace.list", "elastic_request_link", "success", "none")))
	require.Equal(t, float64(1), testutil.ToFloat64(transport.routeDecisions.WithLabelValues("workspace.list", "elastic_preferred", "open_elastic_request_link", "open_elastic_request_link")))
	require.Equal(t, float64(1), testutil.ToFloat64(transport.elasticEvents.WithLabelValues("link_rejected", "node_mismatch")))
	require.Equal(t, float64(1), testutil.ToFloat64(transport.warmEvents.WithLabelValues("user_interactive", "user_interactive_read_review_v1", "lease_refreshed", "web_api")))
	require.Equal(t, float64(2), testutil.ToFloat64(transport.elasticPool.WithLabelValues("links")))
	require.Equal(t, uint64(1), histogramCountForMetric(t, reg, "agentteam_daemon_transport_request_duration_seconds", map[string]string{
		"endpoint":  "workspace.list",
		"link_mode": "elastic_request_link",
		"outcome":   "success",
	}))
}

func TestDaemonTransportMetricsCollapseUnsafeLabels(t *testing.T) {
	reg := prometheus.NewRegistry()
	transport, err := RegisterDaemonTransport(reg)
	require.NoError(t, err)

	tokenLike := "Bearer super.secret.token"
	localPath := "/Users/example/private/workspace"
	transport.RecordRemoteRequest(tokenLike, "ws://127.0.0.1/raw", "panic with raw socket", localPath, time.Millisecond)
	transport.RecordRouteDecision(tokenLike, "elastic_preferred", "elastic_request_link", localPath)
	transport.RecordElasticEvent("link_rejected", tokenLike)
	transport.RecordWarmEvent("user@123", "workspace_private_profile", "link_id_"+tokenLike, localPath)
	transport.SetElasticPool("machine_mac_123", 7)

	require.Equal(t, float64(1), testutil.ToFloat64(transport.requests.WithLabelValues(labelUnknown, labelUnknown, labelUnknown, labelUnknown)))
	require.Equal(t, float64(1), testutil.ToFloat64(transport.routeDecisions.WithLabelValues(labelUnknown, "elastic_preferred", "elastic_request_link", labelUnknown)))
	require.Equal(t, float64(1), testutil.ToFloat64(transport.elasticEvents.WithLabelValues("link_rejected", labelUnknown)))
	require.Equal(t, float64(1), testutil.ToFloat64(transport.warmEvents.WithLabelValues("unknown", "unknown", "unknown", "unknown")))
	require.Equal(t, float64(7), testutil.ToFloat64(transport.elasticPool.WithLabelValues(labelUnknown)))

	rendered := collectMetricText(t, reg)
	require.NotContains(t, rendered, "super.secret.token")
	require.NotContains(t, rendered, "/Users/example/private")
	require.NotContains(t, rendered, "127.0.0.1")
}

func collectMetricText(t *testing.T, gatherer prometheus.Gatherer) string {
	t.Helper()
	metrics, err := gatherer.Gather()
	require.NoError(t, err)
	var builder strings.Builder
	for _, family := range metrics {
		builder.WriteString(family.GetName())
		builder.WriteByte('\n')
		for _, metric := range family.GetMetric() {
			for _, label := range metric.GetLabel() {
				builder.WriteString(label.GetName())
				builder.WriteByte('=')
				builder.WriteString(label.GetValue())
				builder.WriteByte('\n')
			}
		}
	}
	return builder.String()
}
