package main

import (
	"log"
	"runtime"
	"sync/atomic"
	"time"
)

// HealthMonitor tracks server health metrics
type HealthMonitor struct {
	server        *Server
	totalClients  int64
	totalMessages int64
	startTime     time.Time
	ticker        *time.Ticker
	shutdown      chan bool
}

func NewHealthMonitor(server *Server) *HealthMonitor {
	return &HealthMonitor{
		server:    server,
		startTime: time.Now(),
		shutdown:  make(chan bool),
	}
}

func (h *HealthMonitor) Start() {
	h.ticker = time.NewTicker(5 * time.Minute) // Log stats every 5 minutes
	go h.monitor()
}

func (h *HealthMonitor) Stop() {
	if h.ticker != nil {
		h.ticker.Stop()
	}
	close(h.shutdown)
}

func (h *HealthMonitor) IncrementClients() {
	atomic.AddInt64(&h.totalClients, 1)
}

func (h *HealthMonitor) DecrementClients() {
	atomic.AddInt64(&h.totalClients, -1)
}

func (h *HealthMonitor) IncrementMessages() {
	atomic.AddInt64(&h.totalMessages, 1)
}

func (h *HealthMonitor) monitor() {
	for {
		select {
		case <-h.ticker.C:
			h.logHealthStats()
		case <-h.shutdown:
			return
		}
	}
}

func (h *HealthMonitor) logHealthStats() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)

	h.server.mu.RLock()
	clientCount := len(h.server.clients)
	channelCount := len(h.server.channels)
	h.server.mu.RUnlock()

	totalClients := atomic.LoadInt64(&h.totalClients)
	totalMessages := atomic.LoadInt64(&h.totalMessages)
	uptime := time.Since(h.startTime)

	log.Printf("Health Stats - Uptime: %v, Clients: %d, Channels: %d, Total Clients: %d, Total Messages: %d",
		uptime.Round(time.Second), clientCount, channelCount, totalClients, totalMessages)

	log.Printf("Memory Stats - Alloc: %d KB, Sys: %d KB, NumGC: %d, Goroutines: %d",
		bToKb(m.Alloc), bToKb(m.Sys), m.NumGC, runtime.NumGoroutine())

	// Alert if memory usage is high
	if m.Alloc > 100*1024*1024 { // 100MB
		log.Printf("WARNING: High memory usage detected: %d MB", bToMb(m.Alloc))
	}

	// Alert if too many goroutines
	if runtime.NumGoroutine() > 1000 {
		log.Printf("WARNING: High goroutine count: %d", runtime.NumGoroutine())
	}
}

func bToKb(b uint64) uint64 {
	return b / 1024
}

func bToMb(b uint64) uint64 {
	return b / 1024 / 1024
}
