package connector_events

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

var (
	connectorEventClaimsTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "nexuscrm_connector_event_claims_total",
			Help: "Connector event claim attempts by claim mode and result.",
		},
		[]string{"mode", "result"},
	)

	connectorEventFinalizationsTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "nexuscrm_connector_event_finalizations_total",
			Help: "Connector event finalization outcomes.",
		},
		[]string{"outcome", "result"},
	)

	connectorQueueDepth = promauto.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "nexuscrm_connector_event_queue_depth",
			Help: "Connector event queue depth by low-cardinality global state.",
		},
		[]string{"state"},
	)

	connectorQueueOldestAgeSeconds = promauto.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "nexuscrm_connector_event_queue_oldest_age_seconds",
			Help: "Age in seconds of the oldest connector event in each low-cardinality global bucket.",
		},
		[]string{"bucket"},
	)

	connectorEventEnqueueStageDurationSeconds = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "nexuscrm_connector_event_enqueue_stage_duration_seconds",
			Help:    "Connector event enqueue batch stage duration by generic stage and outcome.",
			Buckets: []float64{0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60, 120, 300, 600, 900},
		},
		[]string{"stage", "outcome"},
	)

	connectorEventEnqueueBatchRows = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "nexuscrm_connector_event_enqueue_batch_rows",
			Help:    "Rows handled by connector Event enqueue batches, separated into immutable facts and executable WorkItem shapes.",
			Buckets: []float64{1, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000},
		},
		[]string{"kind"},
	)
)

func recordConnectorEventClaim(mode, result string) {
	connectorEventClaimsTotal.WithLabelValues(mode, result).Inc()
}

func recordConnectorEventFinalize(outcome, result string) {
	connectorEventFinalizationsTotal.WithLabelValues(outcome, result).Inc()
}

// InitializeLiveQueueMetrics creates every fixed connector queue series without
// changing an already-published value. Hosts that defer the first exact queue
// observation can call this during startup so metric discovery remains stable
// without issuing a database read.
func InitializeLiveQueueMetrics() {
	for _, state := range []string{
		"pending",
		"due",
		"failed_due",
		"failed_not_due",
		"processing",
		"stale_processing",
	} {
		connectorQueueDepth.WithLabelValues(state).Add(0)
	}
	for _, bucket := range []string{
		"pending",
		"due",
		"failed_due",
		"processing",
	} {
		connectorQueueOldestAgeSeconds.WithLabelValues(bucket).Add(0)
	}
}

func observeConnectorLiveQueueStats(stats QueueBacklogStats) {
	connectorQueueDepth.WithLabelValues("pending").Set(float64(stats.Pending))
	connectorQueueDepth.WithLabelValues("due").Set(float64(stats.Due))
	connectorQueueDepth.WithLabelValues("failed_due").Set(float64(stats.FailedDue))
	connectorQueueDepth.WithLabelValues("failed_not_due").Set(float64(stats.FailedNotDue))
	connectorQueueDepth.WithLabelValues("processing").Set(float64(stats.Processing))
	connectorQueueDepth.WithLabelValues("stale_processing").Set(float64(stats.StaleProcessing))
	connectorQueueOldestAgeSeconds.WithLabelValues("pending").Set(float64(stats.OldestPendingAgeSeconds))
	connectorQueueOldestAgeSeconds.WithLabelValues("due").Set(float64(stats.OldestDueAgeSeconds))
	connectorQueueOldestAgeSeconds.WithLabelValues("failed_due").Set(float64(stats.OldestFailedAgeSeconds))
	connectorQueueOldestAgeSeconds.WithLabelValues("processing").Set(float64(stats.OldestProcessingSeconds))
}

func recordConnectorEventEnqueueStageDuration(stage string, outcome string, seconds float64) {
	if stage == "" {
		stage = "unknown"
	}
	if outcome == "" {
		outcome = "unknown"
	}
	connectorEventEnqueueStageDurationSeconds.WithLabelValues(stage, outcome).Observe(seconds)
}

func recordConnectorEventEnqueueBatchRows(kind string, rows int) {
	if kind == "" {
		kind = "unknown"
	}
	connectorEventEnqueueBatchRows.WithLabelValues(kind).Observe(float64(rows))
}
