package voice

import (
	"errors"
	"sync"
)

var (
	ErrChannelNotFound = errors.New("channel not found")
	ErrUserNotFound    = errors.New("user not found")
)

// Subscriber is a function that receives voice packets
type Subscriber func(*Packet) error

// Router handles voice packet routing
type Router struct {
	channels      map[string][]Subscriber // channelID -> list of subscribers
	channelLocks  map[string]*sync.RWMutex
	mu            sync.RWMutex
}

// NewRouter creates a new voice router
func NewRouter() *Router {
	return &Router{
		channels:     make(map[string][]Subscriber),
		channelLocks: make(map[string]*sync.RWMutex),
	}
}

// PublishPacket publishes a voice packet to a channel
func (r *Router) PublishPacket(packet *Packet) error {
	if packet == nil {
		return errors.New("packet is nil")
	}

	channelID := packet.ChannelID

	// Get or create channel lock
	r.mu.Lock()
	channelLock, exists := r.channelLocks[channelID]
	if !exists {
		channelLock = &sync.RWMutex{}
		r.channelLocks[channelID] = channelLock
	}
	r.mu.Unlock()

	// Get subscribers
	channelLock.RLock()
	subscribers, exists := r.channels[channelID]
	if !exists || len(subscribers) == 0 {
		channelLock.RUnlock()
		return nil // No subscribers, silent fail
	}

	// Make a copy to avoid holding lock during send
	subscribersCopy := make([]Subscriber, len(subscribers))
	copy(subscribersCopy, subscribers)
	channelLock.RUnlock()

	// Send to all subscribers
	for _, subscriber := range subscribersCopy {
		if subscriber != nil {
			_ = subscriber(packet) // Ignore errors from individual subscribers
		}
	}

	return nil
}

// Subscribe subscribes to voice packets for a channel
func (r *Router) Subscribe(channelID string, subscriber Subscriber) {
	if subscriber == nil {
		return
	}

	r.mu.Lock()
	channelLock, exists := r.channelLocks[channelID]
	if !exists {
		channelLock = &sync.RWMutex{}
		r.channelLocks[channelID] = channelLock
	}
	r.mu.Unlock()

	channelLock.Lock()
	defer channelLock.Unlock()

	r.channels[channelID] = append(r.channels[channelID], subscriber)
}

// Unsubscribe removes a subscriber from a channel
// Note: This function doesn't actually remove the subscriber since functions
// can't be compared in Go. Subscribers are implicitly removed on disconnect.
func (r *Router) Unsubscribe(channelID string, subscriber Subscriber) {
	// Placeholder - in production, track subscribers by ID instead of function pointer
	_ = subscriber
	_ = channelID
}

// GetSubscriberCount returns number of subscribers for a channel
func (r *Router) GetSubscriberCount(channelID string) int {
	r.mu.RLock()
	channelLock, exists := r.channelLocks[channelID]
	if !exists {
		r.mu.RUnlock()
		return 0
	}
	r.mu.RUnlock()

	channelLock.RLock()
	defer channelLock.RUnlock()

	subscribers, exists := r.channels[channelID]
	if !exists {
		return 0
	}

	return len(subscribers)
}
