package voice

import (
	"sync"
	"testing"
)

func TestPublishPacket(t *testing.T) {
	router := NewRouter()

	packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio data"), 12345)

	err := router.PublishPacket(packet)
	if err != nil {
		t.Errorf("PublishPacket() error = %v", err)
	}

	// Test with nil packet
	err = router.PublishPacket(nil)
	if err == nil {
		t.Error("PublishPacket() should error on nil packet")
	}
}

func TestSubscribe(t *testing.T) {
	router := NewRouter()
	channelID := "channel-1"

	receivedPackets := make([]*Packet, 0)
	var mu sync.Mutex

	subscriber := func(p *Packet) error {
		mu.Lock()
		receivedPackets = append(receivedPackets, p)
		mu.Unlock()
		return nil
	}

	router.Subscribe(channelID, subscriber)

	// Publish packet
	packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio"), 12345)
	router.PublishPacket(packet)

	// Give some time for async processing
	if len(receivedPackets) != 1 {
		t.Errorf("Expected 1 received packet, got %d", len(receivedPackets))
	}
}

func TestMultipleSubscribers(t *testing.T) {
	router := NewRouter()
	channelID := "channel-1"

	received1 := make([]*Packet, 0)
	received2 := make([]*Packet, 0)
	var mu1, mu2 sync.Mutex

	subscriber1 := func(p *Packet) error {
		mu1.Lock()
		received1 = append(received1, p)
		mu1.Unlock()
		return nil
	}

	subscriber2 := func(p *Packet) error {
		mu2.Lock()
		received2 = append(received2, p)
		mu2.Unlock()
		return nil
	}

	router.Subscribe(channelID, subscriber1)
	router.Subscribe(channelID, subscriber2)

	packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio"), 12345)
	router.PublishPacket(packet)

	if len(received1) != 1 {
		t.Errorf("Subscriber1 expected 1 packet, got %d", len(received1))
	}

	if len(received2) != 1 {
		t.Errorf("Subscriber2 expected 1 packet, got %d", len(received2))
	}
}

func TestUnsubscribe(t *testing.T) {
	router := NewRouter()
	channelID := "channel-1"

	subscriber := func(p *Packet) error {
		return nil
	}

	router.Subscribe(channelID, subscriber)
	count := router.GetSubscriberCount(channelID)
	if count != 1 {
		t.Errorf("Expected 1 subscriber, got %d", count)
	}

	// Note: Unsubscribe is a placeholder in this implementation
	// In production, we'd track subscribers by ID for proper cleanup
	router.Unsubscribe(channelID, subscriber)
}

func TestGetSubscriberCount(t *testing.T) {
	router := NewRouter()
	channelID := "channel-1"

	subscriber := func(p *Packet) error { return nil }

	// Initially no subscribers
	count := router.GetSubscriberCount(channelID)
	if count != 0 {
		t.Errorf("Expected 0 subscribers, got %d", count)
	}

	// Add subscriber
	router.Subscribe(channelID, subscriber)
	count = router.GetSubscriberCount(channelID)
	if count != 1 {
		t.Errorf("Expected 1 subscriber, got %d", count)
	}

	// Add another subscriber
	router.Subscribe(channelID, subscriber)
	count = router.GetSubscriberCount(channelID)
	if count != 2 {
		t.Errorf("Expected 2 subscribers, got %d", count)
	}

	// Note: Unsubscribe is a placeholder - doesn't actually remove in current implementation
	router.Unsubscribe(channelID, subscriber)
}

func TestNilSubscriber(t *testing.T) {
	router := NewRouter()
	channelID := "channel-1"

	// Subscribe with nil should not error
	router.Subscribe(channelID, nil)

	// Should handle gracefully
	packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio"), 12345)
	err := router.PublishPacket(packet)
	if err != nil {
		t.Errorf("PublishPacket() with nil subscriber error = %v", err)
	}
}

func TestMultipleChannels(t *testing.T) {
	router := NewRouter()

	received1 := make([]*Packet, 0)
	received2 := make([]*Packet, 0)
	var mu1, mu2 sync.Mutex

	subscriber1 := func(p *Packet) error {
		mu1.Lock()
		received1 = append(received1, p)
		mu1.Unlock()
		return nil
	}

	subscriber2 := func(p *Packet) error {
		mu2.Lock()
		received2 = append(received2, p)
		mu2.Unlock()
		return nil
	}

	// Subscribe to different channels
	router.Subscribe("channel-1", subscriber1)
	router.Subscribe("channel-2", subscriber2)

	// Publish to channel-1
	packet1 := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio"), 12345)
	router.PublishPacket(packet1)

	// Publish to channel-2
	packet2 := NewPacket("user-2", "channel-2", 1, 1000, 5000, []byte("audio"), 12345)
	router.PublishPacket(packet2)

	if len(received1) != 1 {
		t.Errorf("Channel-1 subscriber expected 1 packet, got %d", len(received1))
	}

	if len(received2) != 1 {
		t.Errorf("Channel-2 subscriber expected 1 packet, got %d", len(received2))
	}
}

func TestPacketSize(t *testing.T) {
	tests := []struct {
		name     string
		payload  []byte
		wantSize int
	}{
		{
			name:     "empty payload",
			payload:  []byte{},
			wantSize: 0,
		},
		{
			name:     "small payload",
			payload:  []byte("audio"),
			wantSize: 5,
		},
		{
			name:     "large payload",
			payload:  make([]byte, 1024),
			wantSize: 1024,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, tt.payload, 12345)

			if packet.Size() != tt.wantSize {
				t.Errorf("Packet.Size() = %d, want %d", packet.Size(), tt.wantSize)
			}
		})
	}
}

func TestPacketFields(t *testing.T) {
	payload := []byte("test audio")
	packet := NewPacket("user-1", "channel-1", 42, 1000, 5000, payload, 12345)

	if packet.SourceUserID != "user-1" {
		t.Errorf("SourceUserID = %s, want user-1", packet.SourceUserID)
	}

	if packet.ChannelID != "channel-1" {
		t.Errorf("ChannelID = %s, want channel-1", packet.ChannelID)
	}

	if packet.SequenceNum != 42 {
		t.Errorf("SequenceNum = %d, want 42", packet.SequenceNum)
	}

	if packet.Timestamp != 1000 {
		t.Errorf("Timestamp = %d, want 1000", packet.Timestamp)
	}

	if packet.SSRC != 5000 {
		t.Errorf("SSRC = %d, want 5000", packet.SSRC)
	}

	if packet.ClientTime != 12345 {
		t.Errorf("ClientTime = %d, want 12345", packet.ClientTime)
	}

	if string(packet.Payload) != "test audio" {
		t.Errorf("Payload = %s, want 'test audio'", string(packet.Payload))
	}
}

func TestConcurrentPublish(t *testing.T) {
	router := NewRouter()
	channelID := "channel-1"

	receivedCount := 0
	var mu sync.Mutex

	subscriber := func(p *Packet) error {
		mu.Lock()
		receivedCount++
		mu.Unlock()
		return nil
	}

	router.Subscribe(channelID, subscriber)

	// Publish packets concurrently from multiple users
	done := make(chan bool, 10)
	for i := 0; i < 10; i++ {
		go func(userID string, seqNum uint32) {
			packet := NewPacket(userID, channelID, seqNum, uint32(1000+seqNum), 5000, []byte("audio"), 12345)
			router.PublishPacket(packet)
			done <- true
		}(("user-" + string(rune(i))), uint32(i))
	}

	for i := 0; i < 10; i++ {
		<-done
	}

	if receivedCount != 10 {
		t.Errorf("Expected 10 received packets, got %d", receivedCount)
	}
}

func TestUnsubscribeNonexistent(t *testing.T) {
	router := NewRouter()
	channelID := "channel-1"

	subscriber := func(p *Packet) error { return nil }

	// Should not error when unsubscribing from nonexistent channel
	router.Unsubscribe(channelID, subscriber)

	// Should not error when unsubscribing nonexistent subscriber
	router.Subscribe(channelID, subscriber)
	router.Unsubscribe(channelID, func(p *Packet) error { return nil })

	// Note: Unsubscribe is a placeholder, so count remains 1
	count := router.GetSubscriberCount(channelID)
	if count != 1 {
		t.Errorf("Expected 1 subscriber (unsubscribe is placeholder), got %d", count)
	}
}
