// Package metrics provides centralized metrics tracking for the RouteWatch application
package metrics

import (
	"sync"
	"sync/atomic"
	"time"

	"github.com/rcrowley/go-metrics"
)

// Tracker provides centralized metrics tracking
type Tracker struct {
	mu             sync.RWMutex
	registry       metrics.Registry
	connectedSince time.Time
	isConnected    atomic.Bool

	// Stream metrics
	messageCounter metrics.Counter
	byteCounter    metrics.Counter
	messageRate    metrics.Meter
	byteRate       metrics.Meter

	// Route update metrics
	ipv4UpdateRate metrics.Meter
	ipv6UpdateRate metrics.Meter
}

// New creates a new metrics tracker
func New() *Tracker {
	registry := metrics.NewRegistry()

	return &Tracker{
		registry:       registry,
		messageCounter: metrics.NewCounter(),
		byteCounter:    metrics.NewCounter(),
		messageRate:    metrics.NewMeter(),
		byteRate:       metrics.NewMeter(),
		ipv4UpdateRate: metrics.NewMeter(),
		ipv6UpdateRate: metrics.NewMeter(),
	}
}

// SetConnected updates the connection status
func (t *Tracker) SetConnected(connected bool) {
	t.isConnected.Store(connected)
	if connected {
		t.mu.Lock()
		t.connectedSince = time.Now()
		t.mu.Unlock()
	}
}

// IsConnected returns the current connection status
func (t *Tracker) IsConnected() bool {
	return t.isConnected.Load()
}

// RecordMessage records a received message and its size
func (t *Tracker) RecordMessage(bytes int64) {
	t.messageCounter.Inc(1)
	t.byteCounter.Inc(bytes)
	t.messageRate.Mark(1)
	t.byteRate.Mark(bytes)
}

// GetStreamMetrics returns current streaming metrics
func (t *Tracker) GetStreamMetrics() StreamMetrics {
	t.mu.RLock()
	connectedSince := t.connectedSince
	t.mu.RUnlock()

	const bitsPerByte = 8

	// Safely convert counters to uint64
	msgCount := t.messageCounter.Count()
	byteCount := t.byteCounter.Count()

	var totalMessages, totalBytes uint64
	if msgCount >= 0 {
		totalMessages = uint64(msgCount)
	}
	if byteCount >= 0 {
		totalBytes = uint64(byteCount)
	}

	return StreamMetrics{
		TotalMessages:  totalMessages,
		TotalBytes:     totalBytes,
		ConnectedSince: connectedSince,
		Connected:      t.isConnected.Load(),
		MessagesPerSec: t.messageRate.Rate1(),
		BitsPerSec:     t.byteRate.Rate1() * bitsPerByte,
	}
}

// RecordIPv4Update records an IPv4 route update
func (t *Tracker) RecordIPv4Update() {
	t.ipv4UpdateRate.Mark(1)
}

// RecordIPv6Update records an IPv6 route update
func (t *Tracker) RecordIPv6Update() {
	t.ipv6UpdateRate.Mark(1)
}

// GetRouteMetrics returns current route update metrics
func (t *Tracker) GetRouteMetrics() RouteMetrics {
	return RouteMetrics{
		IPv4UpdatesPerSec: t.ipv4UpdateRate.Rate1(),
		IPv6UpdatesPerSec: t.ipv6UpdateRate.Rate1(),
	}
}

// StreamMetrics contains streaming statistics
type StreamMetrics struct {
	TotalMessages  uint64
	TotalBytes     uint64
	ConnectedSince time.Time
	Connected      bool
	MessagesPerSec float64
	BitsPerSec     float64
}

// RouteMetrics contains route update statistics
type RouteMetrics struct {
	IPv4UpdatesPerSec float64
	IPv6UpdatesPerSec float64
}
