package web

import (
	"context"
	"sync"

	"github.com/google/uuid"
)

type DiscussionEvent struct {
	TabloID       uuid.UUID `json:"tabloId"`
	MessageID     uuid.UUID `json:"messageId"`
	AuthorUserID  uuid.UUID `json:"authorUserId"`
	MessageHTML   string    `json:"messageHtml"`
	RefreshUnread bool      `json:"refreshUnread"`
}

type DiscussionRealtime interface {
	Subscribe(ctx context.Context, tabloID uuid.UUID) (<-chan DiscussionEvent, func())
	Publish(event DiscussionEvent)
}

type DiscussionBroker struct {
	mu          sync.Mutex
	nextID      int
	subscribers map[uuid.UUID]map[int]chan DiscussionEvent
}

func NewDiscussionBroker() *DiscussionBroker {
	return &DiscussionBroker{subscribers: make(map[uuid.UUID]map[int]chan DiscussionEvent)}
}

func (b *DiscussionBroker) Subscribe(ctx context.Context, tabloID uuid.UUID) (<-chan DiscussionEvent, func()) {
	ch := make(chan DiscussionEvent, 8)

	b.mu.Lock()
	b.nextID++
	id := b.nextID
	if b.subscribers[tabloID] == nil {
		b.subscribers[tabloID] = make(map[int]chan DiscussionEvent)
	}
	b.subscribers[tabloID][id] = ch
	b.mu.Unlock()

	var once sync.Once
	unsubscribe := func() {
		once.Do(func() {
			b.mu.Lock()
			if subscribers := b.subscribers[tabloID]; subscribers != nil {
				delete(subscribers, id)
				if len(subscribers) == 0 {
					delete(b.subscribers, tabloID)
				}
			}
			b.mu.Unlock()
			close(ch)
		})
	}

	go func() {
		<-ctx.Done()
		unsubscribe()
	}()

	return ch, unsubscribe
}

func (b *DiscussionBroker) Publish(event DiscussionEvent) {
	b.mu.Lock()
	defer b.mu.Unlock()

	for _, ch := range b.subscribers[event.TabloID] {
		select {
		case ch <- event:
		default:
		}
	}
}

func (b *DiscussionBroker) SubscriberCount(tabloID uuid.UUID) int {
	b.mu.Lock()
	defer b.mu.Unlock()
	return len(b.subscribers[tabloID])
}
