package realtime

import (
	"encoding/json"
	"log/slog"
	"sync"
)

type Event struct {
	Type string `json:"type"`
	Data any    `json:"data"`
}

type Client struct {
	send chan []byte
}

type Hub struct {
	logger  *slog.Logger
	mu      sync.RWMutex
	clients map[*Client]struct{}
}

func NewHub(logger *slog.Logger) *Hub {
	return &Hub{
		logger:  logger,
		clients: make(map[*Client]struct{}),
	}
}

func (h *Hub) NewClient(buffer int) *Client {
	return &Client{send: make(chan []byte, buffer)}
}

func (h *Hub) Register(client *Client) {
	h.mu.Lock()
	defer h.mu.Unlock()
	h.clients[client] = struct{}{}
}

func (h *Hub) Unregister(client *Client) {
	h.mu.Lock()
	defer h.mu.Unlock()
	if _, ok := h.clients[client]; ok {
		delete(h.clients, client)
		close(client.send)
	}
}

func (h *Hub) Broadcast(event Event) {
	payload, err := json.Marshal(event)
	if err != nil {
		h.logger.Error("marshal realtime event", "error", err)
		return
	}

	h.mu.RLock()
	defer h.mu.RUnlock()
	for client := range h.clients {
		select {
		case client.send <- payload:
		default:
			h.logger.Warn("dropping realtime event for slow client")
		}
	}
}

func (c *Client) Send() <-chan []byte {
	return c.send
}
