package events

import (
	"testing"

	panelv1 "github.com/dbledeez/panel/proto/panel/v1"
)

func logEvent(agentID, instanceID string) *panelv1.Event {
	return &panelv1.Event{
		AgentId: agentID,
		Payload: &panelv1.Event_Log{Log: &panelv1.LogLine{InstanceId: instanceID, Line: "x"}},
	}
}

func statsEvent(agentID, instanceID string) *panelv1.Event {
	return &panelv1.Event{
		AgentId: agentID,
		Payload: &panelv1.Event_InstanceStats{InstanceStats: &panelv1.InstanceStatsUpdate{InstanceId: instanceID}},
	}
}

// drain returns however many events are immediately buffered.
func drain(s *Subscription) int {
	n := 0
	for {
		select {
		case <-s.Events():
			n++
		default:
			return n
		}
	}
}

func TestFilterExcludeLogs(t *testing.T) {
	b := New(16)
	sub := b.Subscribe(Filter{ExcludeLogs: true})
	defer sub.Close()

	b.Publish(logEvent("a1", "i1"))
	b.Publish(statsEvent("a1", "i1"))
	b.Publish(logEvent("a2", "i2"))

	if got := drain(sub); got != 1 {
		t.Fatalf("ExcludeLogs subscriber got %d events, want 1 (stats only)", got)
	}
}

func TestFilterInstanceAndAgent(t *testing.T) {
	b := New(16)
	byInst := b.Subscribe(Filter{InstanceID: "i1"})
	defer byInst.Close()
	byAgent := b.Subscribe(Filter{AgentID: "a2"})
	defer byAgent.Close()
	all := b.Subscribe(Filter{})
	defer all.Close()

	b.Publish(logEvent("a1", "i1"))
	b.Publish(statsEvent("a2", "i2"))

	if got := drain(byInst); got != 1 {
		t.Fatalf("InstanceID filter got %d, want 1", got)
	}
	if got := drain(byAgent); got != 1 {
		t.Fatalf("AgentID filter got %d, want 1", got)
	}
	if got := drain(all); got != 2 {
		t.Fatalf("unfiltered got %d, want 2", got)
	}
}

func TestDropOnFullBuffer(t *testing.T) {
	b := New(2)
	sub := b.Subscribe(Filter{})
	defer sub.Close()
	for i := 0; i < 5; i++ {
		b.Publish(statsEvent("a1", "i1"))
	}
	if got := drain(sub); got != 2 {
		t.Fatalf("buffered %d, want 2", got)
	}
	if d := sub.Dropped(); d != 3 {
		t.Fatalf("dropped %d, want 3", d)
	}
}
