package im

import "sync"

// liveTaskUnreadPublishKey identifies the member-owned browser projection that
// must observe Task unread updates in publish order.
type liveTaskUnreadPublishKey struct {
	workspaceID string
	memberID    string
	scopeID     string
}

// liveTaskUnreadPublishSequencer keeps one mutex per currently active key.
// Entries are reference-counted and removed after the publisher and all of its
// waiters leave, so completed Tasks do not accumulate in emitter memory.
type liveTaskUnreadPublishSequencer struct {
	mu      sync.Mutex
	entries map[liveTaskUnreadPublishKey]*liveTaskUnreadPublishEntry
}

type liveTaskUnreadPublishEntry struct {
	mu   sync.Mutex
	refs int
}

func (sequencer *liveTaskUnreadPublishSequencer) acquire(key liveTaskUnreadPublishKey) func() {
	sequencer.mu.Lock()
	if sequencer.entries == nil {
		sequencer.entries = make(map[liveTaskUnreadPublishKey]*liveTaskUnreadPublishEntry)
	}
	entry := sequencer.entries[key]
	if entry == nil {
		entry = &liveTaskUnreadPublishEntry{}
		sequencer.entries[key] = entry
	}
	entry.refs++
	sequencer.mu.Unlock()

	entry.mu.Lock()
	return func() {
		entry.mu.Unlock()

		sequencer.mu.Lock()
		entry.refs--
		if entry.refs == 0 {
			delete(sequencer.entries, key)
		}
		sequencer.mu.Unlock()
	}
}
