package main

import (
	"fmt"
	"github.com/go-redis/redis/v8"
	"math"
	"os"
	"strings"
	"time"
)

type eventCounts struct {
	All           int
	Members       int
	GroupSizeFull int
	GroupSizeHalf int
}

const tarpitFactor = 1000.0

func main() {

	// konfigurace redis klienta
	options, err := redis.ParseURL(os.Getenv("CFG_REDIS"))
	if err != nil {
		panic(err)
	}

	// redis klient a kontext
	rdb := redis.NewClient(options)
	ctx := rdb.Context()

	// ukonceni prace redis klienta
	defer func() {
		err := rdb.Close()
		if err != nil {
			panic(err)
		}
	}()

	lastPub := make(map[string]time.Time)

	// main loop
	ticker := time.Tick(time.Second * 1)

	for now := range ticker {

		online := make(map[string]eventCounts)

		iter := rdb.Scan(ctx, 0, "live:*", 0).Iterator()

		for iter.Next(ctx) {
			key := strings.Split(iter.Val(), ":")

			eventID := key[1]
			isMember := key[2] == "1"

			// pocitani
			event := online[eventID]
			event.All++
			if isMember {
				event.Members++
			}
			event.GroupSizeFull, event.GroupSizeHalf = member_group_size(event.All)

			online[key[1]] = event
		}

		if err := iter.Err(); err != nil {
			panic(err)
		}

		// publsh counts
		for event, count := range online {

			elapsed := now.Sub(lastPub[event]).Round(time.Second).Seconds()

			if elapsed < float64(count.All)/tarpitFactor {
				break
			}

			lastPub[event] = now

			topic := fmt.Sprintf("online:%s", event)
			message := fmt.Sprintf("%v", count)
			message = message[1 : len(message)-1]

			if os.Getenv("DEBUG") != "" {
				fmt.Println(topic, message)
			}

			err = rdb.Publish(ctx, topic, message).Err()
			if err != nil {
				panic(err)
			}
		}
	}
}

func member_group_size(count int) (full int, half int) {

	min := float64(count) / 100
	max := float64(count) / 5

	group := 2 * math.Sqrt(float64(count))

	if group < min {
		group = min
	}

	if group > max {
		group = max
	}

	full = int(math.Ceil(group))
	half = int(math.Ceil(group / 2))

	return
}