package main

import (
	"errors"
)

type Notifier[TNotification any] struct {
	bufferSize int

	Listeners map[string]chan TNotification
}

func (n *Notifier[TNotification]) Create(id string) error {
	if _, exists := n.Listeners[id]; exists {
		return errors.New("This listener already exists")
	}

	n.Listeners[id] = make(chan TNotification, n.bufferSize)

	return nil
}

var ChannelFullErr = errors.New("Channel is full")

// Ensures the listener exists before sending
func (n *Notifier[TNotification]) SendAndCreate(id string, notification TNotification) error {
	if _, exists := n.Listeners[id]; !exists {
		if err := n.Create(id); err != nil {
			return err
		}
	}

	ch := n.Listeners[id]

	select {
	case ch <- notification:
		return nil
	default:
		return ChannelFullErr
	}
}

func (n *Notifier[TNotification]) Delete(id string) error {
	if _, exists := n.Listeners[id]; !exists {
		return errors.New("This listener does not exists")
	}

	delete(n.Listeners, id)

	return nil
}

func NewNotifier[TNotification any](bufferSize int) Notifier[TNotification] {
	return Notifier[TNotification]{
		bufferSize: bufferSize,
		Listeners:  make(map[string]chan TNotification),
	}
}

// ----------------------------------

type ChannelSplitter[TNotification any] struct {
	ch chan TNotification

	Listeners map[string]chan TNotification
}

func (s *ChannelSplitter[TNotification]) Listen() {
	go func() {
		for {
			select {
			case msg := <-s.ch:
				for _, v := range s.Listeners {
					v <- msg
				}
			}
		}
	}()
}

func (s *ChannelSplitter[TNotification]) Add(id string) chan TNotification {
	ch := make(chan TNotification)
	s.Listeners[id] = ch

	return ch
}

func (s *ChannelSplitter[TNotification]) Remove(id string) {
	delete(s.Listeners, id)
}

func NewChannelSplitter[TNotification any](ch chan TNotification) ChannelSplitter[TNotification] {
	return ChannelSplitter[TNotification]{
		ch:        ch,
		Listeners: make(map[string]chan TNotification),
	}
}
