package event

import (
	"log/slog"
	"sync"
)

const defaultChannelSize = 64

// Bus is an event bus.
type Bus struct {
	consumers []chan Event
	mu        sync.Mutex
	logger    *slog.Logger
}

// NewBus returns a new event bus.
func NewBus(logger *slog.Logger) *Bus {
	return &Bus{
		logger: logger,
	}
}

// Register registers a consumer for all events.
func (b *Bus) Register() <-chan Event {
	b.mu.Lock()
	defer b.mu.Unlock()

	ch := make(chan Event, defaultChannelSize)
	b.consumers = append(b.consumers, ch)
	return ch
}

// Send sends an event to all registered consumers.
func (b *Bus) Send(evt Event) {
	// The mutex is needed to ensure the backing array of b.consumers cannot be
	// modified under our feet. There is probably a more efficient way to do this
	// but this should be ok.
	b.mu.Lock()
	defer b.mu.Unlock()

	for _, ch := range b.consumers {
		select {
		case ch <- evt:
		default:
			b.logger.Warn("Event dropped", "name", evt.name())
		}
	}
}