package bus

import (
	"container/list"
	"lmika.dev/lmika/hugo-cms/models"
)

type Bus struct {
	subs       *list.List
	eventQueue chan models.Event
}

func New() *Bus {
	return &Bus{
		subs:       list.New(),
		eventQueue: make(chan models.Event, 20),
	}
}

func (b *Bus) Fire(event models.Event) {
	b.eventQueue <- event
}

func (b *Bus) Start() {
	go func() {
		for e := range b.eventQueue {
			switch e.Type {
			case models.EventTypeSubscribe:
				retChan := e.Data.(chan *models.Sub)

				newSub := &models.Sub{C: make(chan models.Event, 1)}
				newSub.Elem = b.subs.PushBack(newSub)

				retChan <- newSub
			case models.EventTypeUnsubscribe:
				sub := e.Data.(*models.Sub)
				close(sub.C)
				b.subs.Remove(sub.Elem)
			default:
				for f := b.subs.Front(); f != nil; f = f.Next() {
					sub := f.Value.(*models.Sub)
					select {
					case sub.C <- e:
					default:
					}
				}
			}
		}
	}()
}

func (b *Bus) Stop() {
	close(b.eventQueue)
}

func (b *Bus) Subscribe() *models.Sub {
	resChan := make(chan *models.Sub)
	b.eventQueue <- models.Event{Type: models.EventTypeSubscribe, Data: resChan}
	return <-resChan
}

func (b *Bus) Unsubscribe(sub *models.Sub) {
	b.eventQueue <- models.Event{Type: models.EventTypeUnsubscribe, Data: sub}
}