package realtime

import (
	"net/http/httptest"
	"testing"
)

func TestExtractToken(t *testing.T) {
	req := httptest.NewRequest("GET", "/ws", nil)
	req.Header.Set("Authorization", "Bearer abc")
	token, ok := extractToken(req)
	if !ok || token != "abc" {
		t.Fatalf("extractToken auth header = (%q, %v), want (abc, true)", token, ok)
	}

	req = httptest.NewRequest("GET", "/ws?token=q1", nil)
	token, ok = extractToken(req)
	if !ok || token != "q1" {
		t.Fatalf("extractToken token query = (%q, %v), want (q1, true)", token, ok)
	}

	req = httptest.NewRequest("GET", "/ws?access_token=q2", nil)
	token, ok = extractToken(req)
	if !ok || token != "q2" {
		t.Fatalf("extractToken access_token query = (%q, %v), want (q2, true)", token, ok)
	}
}

func TestParseSinceCursor(t *testing.T) {
	req := httptest.NewRequest("GET", "/ws?since=42", nil)
	if got := parseSinceCursor(req); got != 42 {
		t.Fatalf("parseSinceCursor() = %d, want 42", got)
	}

	req = httptest.NewRequest("GET", "/ws?since=bad", nil)
	if got := parseSinceCursor(req); got != 0 {
		t.Fatalf("parseSinceCursor() invalid = %d, want 0", got)
	}
}

func TestTokenSessionKeyStable(t *testing.T) {
	a := tokenSessionKey("same-token")
	b := tokenSessionKey("same-token")
	c := tokenSessionKey("other-token")
	if a != b {
		t.Fatalf("session keys for same token differ: %q != %q", a, b)
	}
	if a == c {
		t.Fatalf("session keys for different tokens should differ")
	}
}

func TestRegisterRespectsLimits(t *testing.T) {
	h := NewHub(nil, nil)
	h.SetLimits(2, 1, 10)

	c1 := &conn{userID: "u1", sessionKey: "s1"}
	c2 := &conn{userID: "u1", sessionKey: "s2"}
	c3 := &conn{userID: "u1", sessionKey: "s3"}

	if err := h.register(c1); err != nil {
		t.Fatalf("register c1 error = %v", err)
	}
	if err := h.register(c2); err != nil {
		t.Fatalf("register c2 error = %v", err)
	}
	if err := h.register(c3); err == nil {
		t.Fatalf("register c3 expected user limit error")
	}

	h2 := NewHub(nil, nil)
	h2.SetLimits(5, 1, 10)
	if err := h2.register(&conn{userID: "u1", sessionKey: "s1"}); err != nil {
		t.Fatalf("register first session conn error = %v", err)
	}
	if err := h2.register(&conn{userID: "u1", sessionKey: "s1"}); err == nil {
		t.Fatalf("register second session conn expected session limit error")
	}
}

func TestBroadcastAssignsSequenceAndKeepsReplayBuffer(t *testing.T) {
	h := NewHub(nil, nil)
	h.SetLimits(10, 10, 2)

	h.Broadcast("u1", NewMailCreatedEvent("m1", "a1"))
	h.Broadcast("u1", NewMailUpdatedEvent("m2", "a1"))
	h.Broadcast("u1", NewMailDeletedEvent("m3", "a1"))

	if head := h.HistoryHead("u1"); head != 3 {
		t.Fatalf("HistoryHead() = %d, want 3", head)
	}
	if len(h.history["u1"]) != 2 {
		t.Fatalf("history length = %d, want 2", len(h.history["u1"]))
	}
	if h.history["u1"][0].Seq != 2 || h.history["u1"][1].Seq != 3 {
		t.Fatalf("history seqs = [%d, %d], want [2, 3]", h.history["u1"][0].Seq, h.history["u1"][1].Seq)
	}
}
