//go:build js && wasm

package wasmdb

import (
	"bytes"
	"context"
	"testing"
	"time"

	"git.mleku.dev/mleku/nostr/encoders/event"
	"git.mleku.dev/mleku/nostr/encoders/filter"
	"git.mleku.dev/mleku/nostr/encoders/kind"
	"git.mleku.dev/mleku/nostr/encoders/tag"
	"next.orly.dev/pkg/database/indexes/types"
)

// TestDatabaseOpen tests that we can open an IndexedDB database
func TestDatabaseOpen(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Create a new database instance
	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	// Wait for the database to be ready
	select {
	case <-db.Ready():
		t.Log("Database ready")
	case <-ctx.Done():
		t.Fatal("Timeout waiting for database to be ready")
	}

	t.Log("Database opened successfully")
}

// TestDatabaseMetaStorage tests storing and retrieving metadata
func TestDatabaseMetaStorage(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Test SetMarker and GetMarker
	testKey := "test_key"
	testValue := []byte("test_value_12345")

	err = db.SetMarker(testKey, testValue)
	if err != nil {
		t.Fatalf("Failed to set marker: %v", err)
	}

	retrieved, err := db.GetMarker(testKey)
	if err != nil {
		t.Fatalf("Failed to get marker: %v", err)
	}

	if string(retrieved) != string(testValue) {
		t.Errorf("Retrieved value %q doesn't match expected %q", retrieved, testValue)
	}

	// Test HasMarker
	if !db.HasMarker(testKey) {
		t.Error("HasMarker returned false for existing key")
	}

	if db.HasMarker("nonexistent_key") {
		t.Error("HasMarker returned true for nonexistent key")
	}

	// Test DeleteMarker
	err = db.DeleteMarker(testKey)
	if err != nil {
		t.Fatalf("Failed to delete marker: %v", err)
	}

	if db.HasMarker(testKey) {
		t.Error("HasMarker returned true after deletion")
	}
}

// TestDatabaseSerialCounters tests the serial number generation
func TestDatabaseSerialCounters(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Generate some serials and verify they're incrementing
	serial1, err := db.nextEventSerial()
	if err != nil {
		t.Fatalf("Failed to get first serial: %v", err)
	}

	serial2, err := db.nextEventSerial()
	if err != nil {
		t.Fatalf("Failed to get second serial: %v", err)
	}

	if serial2 != serial1+1 {
		t.Errorf("Serials not incrementing: got %d and %d", serial1, serial2)
	}

	t.Logf("Generated serials: %d, %d", serial1, serial2)
}

// TestDatabaseRelayIdentity tests relay identity key management
func TestDatabaseRelayIdentity(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// First call should create a new identity
	skb, err := db.GetOrCreateRelayIdentitySecret()
	if err != nil {
		t.Fatalf("Failed to get/create relay identity: %v", err)
	}

	if len(skb) != 32 {
		t.Errorf("Expected 32-byte secret key, got %d bytes", len(skb))
	}

	// Second call should return the same key
	skb2, err := db.GetOrCreateRelayIdentitySecret()
	if err != nil {
		t.Fatalf("Failed to get relay identity second time: %v", err)
	}

	if string(skb) != string(skb2) {
		t.Error("GetOrCreateRelayIdentitySecret returned different keys on second call")
	}

	t.Logf("Relay identity key: %x", skb[:8])
}

// TestDatabaseWipe tests the wipe functionality
func TestDatabaseWipe(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Store some data
	err = db.SetMarker("wipe_test_key", []byte("wipe_test_value"))
	if err != nil {
		t.Fatalf("Failed to set marker: %v", err)
	}

	// Wipe the database
	err = db.Wipe()
	if err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Verify data is gone
	if db.HasMarker("wipe_test_key") {
		t.Error("Marker still exists after wipe")
	}

	t.Log("Database wipe successful")
}

// createTestEvent creates a test event with fake ID and signature (for storage testing only)
func createTestEvent(kind uint16, content string, pubkey []byte) *event.E {
	ev := event.New()
	ev.Kind = kind
	ev.Content = []byte(content)
	ev.CreatedAt = time.Now().Unix()
	ev.Tags = tag.NewS()

	// Use provided pubkey or generate a fake one
	if len(pubkey) == 32 {
		ev.Pubkey = pubkey
	} else {
		ev.Pubkey = make([]byte, 32)
		for i := range ev.Pubkey {
			ev.Pubkey[i] = byte(i)
		}
	}

	// Generate a fake ID (normally would be SHA256 of serialized event)
	ev.ID = make([]byte, 32)
	for i := range ev.ID {
		ev.ID[i] = byte(i + 100)
	}

	// Generate a fake signature (won't verify, but storage doesn't need to verify)
	ev.Sig = make([]byte, 64)
	for i := range ev.Sig {
		ev.Sig[i] = byte(i + 200)
	}

	return ev
}

// TestSaveAndFetchEvent tests saving and fetching events
func TestSaveAndFetchEvent(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Wipe the database to start fresh
	db, err := New(ctx, cancel, "/tmp/test", "debug")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create a test event
	ev := createTestEvent(1, "Hello, Nostr!", nil)
	t.Logf("Created event with ID: %x", ev.ID[:8])

	// Save the event
	replaced, err := db.SaveEvent(ctx, ev)
	if err != nil {
		t.Fatalf("Failed to save event: %v", err)
	}
	if replaced {
		t.Error("Expected replaced to be false for new event")
	}

	t.Log("Event saved successfully")

	// Look up the serial by ID
	ser, err := db.GetSerialById(ev.ID)
	if err != nil {
		t.Fatalf("Failed to get serial by ID: %v", err)
	}
	if ser == nil {
		t.Fatal("Got nil serial")
	}
	t.Logf("Event serial: %d", ser.Get())

	// Fetch the event by serial
	fetchedEv, err := db.FetchEventBySerial(ser)
	if err != nil {
		t.Fatalf("Failed to fetch event by serial: %v", err)
	}
	if fetchedEv == nil {
		t.Fatal("Fetched event is nil")
	}

	// Verify the event content matches
	if !bytes.Equal(fetchedEv.ID, ev.ID) {
		t.Errorf("Event ID mismatch: got %x, want %x", fetchedEv.ID[:8], ev.ID[:8])
	}
	if !bytes.Equal(fetchedEv.Content, ev.Content) {
		t.Errorf("Event content mismatch: got %q, want %q", fetchedEv.Content, ev.Content)
	}
	if fetchedEv.Kind != ev.Kind {
		t.Errorf("Event kind mismatch: got %d, want %d", fetchedEv.Kind, ev.Kind)
	}

	t.Log("Event fetched and verified successfully")
}

// TestSaveEventDuplicate tests that saving a duplicate event returns an error
func TestSaveEventDuplicate(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create and save a test event
	ev := createTestEvent(1, "Duplicate test", nil)

	_, err = db.SaveEvent(ctx, ev)
	if err != nil {
		t.Fatalf("Failed to save first event: %v", err)
	}

	// Try to save the same event again
	_, err = db.SaveEvent(ctx, ev)
	if err == nil {
		t.Error("Expected error when saving duplicate event, got nil")
	} else {
		t.Logf("Got expected error for duplicate: %v", err)
	}
}

// TestSaveEventWithTags tests saving an event with tags
func TestSaveEventWithTags(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create an event with tags
	ev := createTestEvent(1, "Event with tags", nil)

	// Make the ID unique
	ev.ID[0] = 0x42

	// Add some tags
	ev.Tags = tag.NewS(
		tag.NewFromAny("t", "nostr"),
		tag.NewFromAny("t", "test"),
	)

	// Save the event
	_, err = db.SaveEvent(ctx, ev)
	if err != nil {
		t.Fatalf("Failed to save event with tags: %v", err)
	}

	// Fetch it back
	ser, err := db.GetSerialById(ev.ID)
	if err != nil {
		t.Fatalf("Failed to get serial: %v", err)
	}

	fetchedEv, err := db.FetchEventBySerial(ser)
	if err != nil {
		t.Fatalf("Failed to fetch event: %v", err)
	}

	// Verify tags
	if fetchedEv.Tags == nil || fetchedEv.Tags.Len() != 2 {
		t.Errorf("Expected 2 tags, got %v", fetchedEv.Tags)
	}

	t.Log("Event with tags saved and fetched successfully")
}

// TestFetchEventsBySerials tests batch fetching of events
func TestFetchEventsBySerials(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create and save multiple events
	var serials []*types.Uint40
	for i := 0; i < 3; i++ {
		ev := createTestEvent(1, "Batch test event", nil)
		ev.ID[0] = byte(0x50 + i) // Make IDs unique

		_, err := db.SaveEvent(ctx, ev)
		if err != nil {
			t.Fatalf("Failed to save event %d: %v", i, err)
		}

		ser, err := db.GetSerialById(ev.ID)
		if err != nil {
			t.Fatalf("Failed to get serial for event %d: %v", i, err)
		}
		serials = append(serials, ser)
	}

	// Batch fetch
	events, err := db.FetchEventsBySerials(serials)
	if err != nil {
		t.Fatalf("Failed to batch fetch events: %v", err)
	}

	if len(events) != 3 {
		t.Errorf("Expected 3 events, got %d", len(events))
	}

	t.Logf("Successfully batch fetched %d events", len(events))
}

// TestGetFullIdPubkeyBySerial tests getting event metadata by serial
func TestGetFullIdPubkeyBySerial(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "debug")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create and save an event
	ev := createTestEvent(1, "Metadata test", nil)
	ev.ID[0] = 0x99 // Make ID unique

	_, err = db.SaveEvent(ctx, ev)
	if err != nil {
		t.Fatalf("Failed to save event: %v", err)
	}

	ser, err := db.GetSerialById(ev.ID)
	if err != nil {
		t.Fatalf("Failed to get serial: %v", err)
	}

	// Get full ID/pubkey/timestamp metadata
	fidpk, err := db.GetFullIdPubkeyBySerial(ser)
	if err != nil {
		t.Fatalf("Failed to get full id pubkey: %v", err)
	}
	if fidpk == nil {
		t.Fatal("Got nil fidpk")
	}

	// Verify the ID matches
	if !bytes.Equal(fidpk.Id, ev.ID) {
		t.Errorf("ID mismatch: got %x, want %x", fidpk.Id[:8], ev.ID[:8])
	}

	t.Logf("Got metadata: ID=%x, Pub=%x, Ts=%d, Ser=%d",
		fidpk.Id[:8], fidpk.Pub[:4], fidpk.Ts, fidpk.Ser)
}

// TestQueryEventsByKind tests querying events by kind
func TestQueryEventsByKind(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create events of different kinds
	ev1 := createTestEvent(1, "Kind 1 event", nil)
	ev1.ID[0] = 0xA1
	ev2 := createTestEvent(1, "Another kind 1", nil)
	ev2.ID[0] = 0xA2
	ev3 := createTestEvent(7, "Kind 7 event", nil)
	ev3.ID[0] = 0xA3

	// Save events
	for _, ev := range []*event.E{ev1, ev2, ev3} {
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Query for kind 1
	f := &filter.F{
		Kinds: kind.NewS(kind.New(1)),
	}

	evs, err := db.QueryEvents(ctx, f)
	if err != nil {
		t.Fatalf("Failed to query events: %v", err)
	}

	if len(evs) != 2 {
		t.Errorf("Expected 2 events of kind 1, got %d", len(evs))
	}

	t.Logf("Query by kind 1 returned %d events", len(evs))
}

// TestQueryEventsByAuthor tests querying events by author pubkey
func TestQueryEventsByAuthor(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create events from different authors
	author1 := make([]byte, 32)
	for i := range author1 {
		author1[i] = 0x11
	}
	author2 := make([]byte, 32)
	for i := range author2 {
		author2[i] = 0x22
	}

	ev1 := createTestEvent(1, "From author 1", author1)
	ev1.ID[0] = 0xB1
	ev2 := createTestEvent(1, "Also from author 1", author1)
	ev2.ID[0] = 0xB2
	ev3 := createTestEvent(1, "From author 2", author2)
	ev3.ID[0] = 0xB3

	// Save events
	for _, ev := range []*event.E{ev1, ev2, ev3} {
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Query for author1
	f := &filter.F{
		Authors: tag.NewFromBytesSlice(author1),
	}

	evs, err := db.QueryEvents(ctx, f)
	if err != nil {
		t.Fatalf("Failed to query events: %v", err)
	}

	if len(evs) != 2 {
		t.Errorf("Expected 2 events from author1, got %d", len(evs))
	}

	t.Logf("Query by author returned %d events", len(evs))
}

// TestCountEvents tests the event counting functionality
func TestCountEvents(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create multiple events
	for i := 0; i < 5; i++ {
		ev := createTestEvent(1, "Count test event", nil)
		ev.ID[0] = byte(0xC0 + i)
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Count all kind 1 events
	f := &filter.F{
		Kinds: kind.NewS(kind.New(1)),
	}

	count, approx, err := db.CountEvents(ctx, f)
	if err != nil {
		t.Fatalf("Failed to count events: %v", err)
	}

	if count != 5 {
		t.Errorf("Expected count of 5, got %d", count)
	}
	if approx {
		t.Log("Count is approximate")
	}

	t.Logf("CountEvents returned %d", count)
}

// TestQueryEventsWithLimit tests applying a limit to query results
func TestQueryEventsWithLimit(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create 10 events
	for i := 0; i < 10; i++ {
		ev := createTestEvent(1, "Limit test event", nil)
		ev.ID[0] = byte(0xD0 + i)
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Query with limit of 3
	limit := uint(3)
	f := &filter.F{
		Kinds: kind.NewS(kind.New(1)),
		Limit: &limit,
	}

	evs, err := db.QueryEvents(ctx, f)
	if err != nil {
		t.Fatalf("Failed to query events: %v", err)
	}

	if len(evs) != 3 {
		t.Errorf("Expected 3 events with limit, got %d", len(evs))
	}

	t.Logf("Query with limit returned %d events", len(evs))
}

// TestQueryEventsByTag tests querying events by tag
func TestQueryEventsByTag(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create events with different tags
	ev1 := createTestEvent(1, "Has bitcoin tag", nil)
	ev1.ID[0] = 0xE1
	ev1.Tags = tag.NewS(
		tag.NewFromAny("t", "bitcoin"),
	)

	ev2 := createTestEvent(1, "Has nostr tag", nil)
	ev2.ID[0] = 0xE2
	ev2.Tags = tag.NewS(
		tag.NewFromAny("t", "nostr"),
	)

	ev3 := createTestEvent(1, "Has bitcoin and nostr tags", nil)
	ev3.ID[0] = 0xE3
	ev3.Tags = tag.NewS(
		tag.NewFromAny("t", "bitcoin"),
		tag.NewFromAny("t", "nostr"),
	)

	// Save events
	for _, ev := range []*event.E{ev1, ev2, ev3} {
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Query for bitcoin tag
	f := &filter.F{
		Tags: tag.NewS(
			tag.NewFromAny("#t", "bitcoin"),
		),
	}

	evs, err := db.QueryEvents(ctx, f)
	if err != nil {
		t.Fatalf("Failed to query events: %v", err)
	}

	if len(evs) != 2 {
		t.Errorf("Expected 2 events with bitcoin tag, got %d", len(evs))
	}

	t.Logf("Query by tag returned %d events", len(evs))
}

// TestQueryForSerials tests the QueryForSerials method
func TestQueryForSerials(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create and save events
	for i := 0; i < 3; i++ {
		ev := createTestEvent(1, "Serial test", nil)
		ev.ID[0] = byte(0xF0 + i)
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Query for serials
	f := &filter.F{
		Kinds: kind.NewS(kind.New(1)),
	}

	sers, err := db.QueryForSerials(ctx, f)
	if err != nil {
		t.Fatalf("Failed to query for serials: %v", err)
	}

	if len(sers) != 3 {
		t.Errorf("Expected 3 serials, got %d", len(sers))
	}

	t.Logf("QueryForSerials returned %d serials", len(sers))
}

// TestDeleteEvent tests deleting an event by ID
func TestDeleteEvent(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create and save an event
	ev := createTestEvent(1, "Event to delete", nil)
	ev.ID[0] = 0xDE

	if _, err := db.SaveEvent(ctx, ev); err != nil {
		t.Fatalf("Failed to save event: %v", err)
	}

	// Verify it exists
	ser, err := db.GetSerialById(ev.ID)
	if err != nil {
		t.Fatalf("Failed to get serial: %v", err)
	}
	if ser == nil {
		t.Fatal("Serial should not be nil after save")
	}

	// Delete the event
	if err := db.DeleteEvent(ctx, ev.ID); err != nil {
		t.Fatalf("Failed to delete event: %v", err)
	}

	// Verify it no longer exists
	ser, err = db.GetSerialById(ev.ID)
	if err == nil && ser != nil {
		t.Error("Event should not exist after deletion")
	}

	t.Log("Event deleted successfully")
}

// TestDeleteEventBySerial tests deleting an event by serial number
func TestDeleteEventBySerial(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create and save an event
	ev := createTestEvent(1, "Event to delete by serial", nil)
	ev.ID[0] = 0xDF

	if _, err := db.SaveEvent(ctx, ev); err != nil {
		t.Fatalf("Failed to save event: %v", err)
	}

	// Get the serial
	ser, err := db.GetSerialById(ev.ID)
	if err != nil {
		t.Fatalf("Failed to get serial: %v", err)
	}

	// Fetch the event
	fetchedEv, err := db.FetchEventBySerial(ser)
	if err != nil {
		t.Fatalf("Failed to fetch event: %v", err)
	}

	// Delete by serial
	if err := db.DeleteEventBySerial(ctx, ser, fetchedEv); err != nil {
		t.Fatalf("Failed to delete event by serial: %v", err)
	}

	// Verify event is gone
	fetchedEv, err = db.FetchEventBySerial(ser)
	if err == nil && fetchedEv != nil {
		t.Error("Event should not exist after deletion by serial")
	}

	t.Log("Event deleted by serial successfully")
}

// TestCheckForDeleted tests that deleted events are properly detected
func TestCheckForDeleted(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create a regular event
	ev := createTestEvent(1, "Event that will be deleted", nil)
	ev.ID[0] = 0xDD
	ev.CreatedAt = time.Now().Unix() - 100 // 100 seconds ago

	if _, err := db.SaveEvent(ctx, ev); err != nil {
		t.Fatalf("Failed to save event: %v", err)
	}

	// Create a kind 5 deletion event referencing it
	// Use binary format for the e-tag value since GetIndexesForEvent hashes the raw value,
	// and NormalizeTagValueForHash converts hex to binary before hashing in filters
	deleteEv := createTestEvent(5, "", ev.Pubkey)
	deleteEv.ID[0] = 0xD5
	deleteEv.CreatedAt = time.Now().Unix() // Now

	// Store the e-tag with binary value in the format matching JSON unmarshal
	// The nostr library stores e/p tag values as 33 bytes (32 bytes + null terminator)
	eTagValue := make([]byte, 33)
	copy(eTagValue[:32], ev.ID)
	eTagValue[32] = 0 // null terminator to match nostr library's binary format
	deleteEv.Tags = tag.NewS(
		tag.NewFromAny("e", string(eTagValue)),
	)

	if _, err := db.SaveEvent(ctx, deleteEv); err != nil {
		t.Fatalf("Failed to save delete event: %v", err)
	}

	// Check if the original event is marked as deleted
	err = db.CheckForDeleted(ev, nil)
	if err == nil {
		t.Error("Expected error indicating event was deleted")
	} else {
		t.Logf("CheckForDeleted correctly detected deletion: %v", err)
	}
}

// ============================================================================
// NIP-43 Membership Tests
// ============================================================================

// TestNIP43AddAndRemoveMember tests adding and removing NIP-43 members
func TestNIP43AddAndRemoveMember(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create a test pubkey
	pubkey := make([]byte, 32)
	for i := range pubkey {
		pubkey[i] = byte(i + 1)
	}

	// Initially should not be a member
	isMember, err := db.IsNIP43Member(pubkey)
	if err != nil {
		t.Fatalf("Failed to check member status: %v", err)
	}
	if isMember {
		t.Error("Expected non-member initially")
	}

	// Add member with invite code
	inviteCode := "TEST-INVITE-123"
	if err := db.AddNIP43Member(pubkey, inviteCode); err != nil {
		t.Fatalf("Failed to add NIP-43 member: %v", err)
	}

	// Should now be a member
	isMember, err = db.IsNIP43Member(pubkey)
	if err != nil {
		t.Fatalf("Failed to check member status: %v", err)
	}
	if !isMember {
		t.Error("Expected to be a member after adding")
	}

	// Get membership details
	membership, err := db.GetNIP43Membership(pubkey)
	if err != nil {
		t.Fatalf("Failed to get membership: %v", err)
	}
	if membership.InviteCode != inviteCode {
		t.Errorf("Invite code mismatch: got %s, want %s", membership.InviteCode, inviteCode)
	}
	if !bytes.Equal(membership.Pubkey, pubkey) {
		t.Error("Pubkey mismatch in membership")
	}

	// Remove member
	if err := db.RemoveNIP43Member(pubkey); err != nil {
		t.Fatalf("Failed to remove member: %v", err)
	}

	// Should no longer be a member
	isMember, err = db.IsNIP43Member(pubkey)
	if err != nil {
		t.Fatalf("Failed to check member status: %v", err)
	}
	if isMember {
		t.Error("Expected non-member after removal")
	}

	t.Log("NIP-43 add/remove member test passed")
}

// TestNIP43GetAllMembers tests retrieving all members
func TestNIP43GetAllMembers(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Add multiple members
	pubkeys := make([][]byte, 3)
	for i := 0; i < 3; i++ {
		pubkeys[i] = make([]byte, 32)
		for j := range pubkeys[i] {
			pubkeys[i][j] = byte((i+1)*10 + j)
		}
		if err := db.AddNIP43Member(pubkeys[i], "invite"+string(rune('A'+i))); err != nil {
			t.Fatalf("Failed to add member %d: %v", i, err)
		}
	}

	// Get all members
	members, err := db.GetAllNIP43Members()
	if err != nil {
		t.Fatalf("Failed to get all members: %v", err)
	}

	if len(members) != 3 {
		t.Errorf("Expected 3 members, got %d", len(members))
	}

	t.Logf("Retrieved %d NIP-43 members", len(members))
}

// TestNIP43InviteCode tests invite code functionality
func TestNIP43InviteCode(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Store a valid invite code (expires in 24 hours)
	validCode := "VALID-CODE-ABC"
	expiresAt := time.Now().Add(24 * time.Hour)
	if err := db.StoreInviteCode(validCode, expiresAt); err != nil {
		t.Fatalf("Failed to store invite code: %v", err)
	}

	// Validate the code
	valid, err := db.ValidateInviteCode(validCode)
	if err != nil {
		t.Fatalf("Failed to validate invite code: %v", err)
	}
	if !valid {
		t.Error("Expected valid invite code to be valid")
	}

	// Check non-existent code
	valid, err = db.ValidateInviteCode("NONEXISTENT")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if valid {
		t.Error("Expected non-existent code to be invalid")
	}

	// Delete the code
	if err := db.DeleteInviteCode(validCode); err != nil {
		t.Fatalf("Failed to delete invite code: %v", err)
	}

	// Should now be invalid
	valid, err = db.ValidateInviteCode(validCode)
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if valid {
		t.Error("Expected deleted code to be invalid")
	}

	t.Log("NIP-43 invite code test passed")
}

// TestNIP43ExpiredInviteCode tests that expired invite codes are invalid
func TestNIP43ExpiredInviteCode(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Store an expired invite code (expired 1 hour ago)
	expiredCode := "EXPIRED-CODE-XYZ"
	expiresAt := time.Now().Add(-1 * time.Hour)
	if err := db.StoreInviteCode(expiredCode, expiresAt); err != nil {
		t.Fatalf("Failed to store invite code: %v", err)
	}

	// Validate the expired code
	valid, err := db.ValidateInviteCode(expiredCode)
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if valid {
		t.Error("Expected expired invite code to be invalid")
	}

	t.Log("Expired invite code correctly detected as invalid")
}

// TestNIP43InvalidPubkeyLength tests that invalid pubkey lengths are rejected
func TestNIP43InvalidPubkeyLength(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Try to add a member with invalid pubkey length
	shortPubkey := make([]byte, 16) // Should be 32
	err = db.AddNIP43Member(shortPubkey, "test")
	if err == nil {
		t.Error("Expected error for invalid pubkey length")
	}

	t.Logf("Correctly rejected invalid pubkey length: %v", err)
}

// ============================================================================
// Subscription Management Tests
// ============================================================================

// TestSubscriptionExtend tests extending subscriptions
func TestSubscriptionExtend(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	pubkey := make([]byte, 32)
	for i := range pubkey {
		pubkey[i] = byte(i + 50)
	}

	// Initially no subscription
	sub, err := db.GetSubscription(pubkey)
	if err != nil {
		t.Fatalf("Failed to get subscription: %v", err)
	}
	if sub != nil {
		t.Error("Expected nil subscription initially")
	}

	// Extend subscription by 30 days
	if err := db.ExtendSubscription(pubkey, 30); err != nil {
		t.Fatalf("Failed to extend subscription: %v", err)
	}

	// Should now have a subscription
	sub, err = db.GetSubscription(pubkey)
	if err != nil {
		t.Fatalf("Failed to get subscription: %v", err)
	}
	if sub == nil {
		t.Fatal("Expected subscription after extension")
	}

	// Verify paid until is in the future
	if sub.PaidUntil.Before(time.Now()) {
		t.Error("PaidUntil should be in the future")
	}

	// Extend again
	if err := db.ExtendSubscription(pubkey, 15); err != nil {
		t.Fatalf("Failed to extend subscription again: %v", err)
	}

	sub2, err := db.GetSubscription(pubkey)
	if err != nil {
		t.Fatalf("Failed to get subscription: %v", err)
	}

	// Second extension should add to first
	if !sub2.PaidUntil.After(sub.PaidUntil) {
		t.Error("Expected PaidUntil to increase after second extension")
	}

	t.Log("Subscription extension test passed")
}

// TestSubscriptionActive tests checking if subscription is active
func TestSubscriptionActive(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	pubkey := make([]byte, 32)
	for i := range pubkey {
		pubkey[i] = byte(i + 60)
	}

	// First check creates a trial subscription
	active, err := db.IsSubscriptionActive(pubkey)
	if err != nil {
		t.Fatalf("Failed to check subscription: %v", err)
	}
	if !active {
		t.Error("Expected new user to have active trial subscription")
	}

	// Second check should still be active
	active, err = db.IsSubscriptionActive(pubkey)
	if err != nil {
		t.Fatalf("Failed to check subscription: %v", err)
	}
	if !active {
		t.Error("Expected subscription to remain active")
	}

	t.Log("Subscription active check passed")
}

// TestBlossomSubscription tests blossom storage subscription
func TestBlossomSubscription(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	pubkey := make([]byte, 32)
	for i := range pubkey {
		pubkey[i] = byte(i + 70)
	}

	// Initially no quota
	quota, err := db.GetBlossomStorageQuota(pubkey)
	if err != nil {
		t.Fatalf("Failed to get quota: %v", err)
	}
	if quota != 0 {
		t.Error("Expected zero quota initially")
	}

	// Add blossom subscription
	if err := db.ExtendBlossomSubscription(pubkey, "premium", 1024, 30); err != nil {
		t.Fatalf("Failed to extend blossom subscription: %v", err)
	}

	// Check quota
	quota, err = db.GetBlossomStorageQuota(pubkey)
	if err != nil {
		t.Fatalf("Failed to get quota: %v", err)
	}
	if quota != 1024 {
		t.Errorf("Expected quota of 1024, got %d", quota)
	}

	// Check subscription details
	sub, err := db.GetSubscription(pubkey)
	if err != nil {
		t.Fatalf("Failed to get subscription: %v", err)
	}
	if sub.BlossomLevel != "premium" {
		t.Errorf("Expected premium level, got %s", sub.BlossomLevel)
	}

	t.Log("Blossom subscription test passed")
}

// TestPaymentHistory tests recording and retrieving payment history
func TestPaymentHistory(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	pubkey := make([]byte, 32)
	for i := range pubkey {
		pubkey[i] = byte(i + 80)
	}

	// Initially no payment history
	payments, err := db.GetPaymentHistory(pubkey)
	if err != nil {
		t.Fatalf("Failed to get payment history: %v", err)
	}
	if len(payments) != 0 {
		t.Error("Expected empty payment history initially")
	}

	// Record a payment
	if err := db.RecordPayment(pubkey, 10000, "lnbc100...", "preimage123"); err != nil {
		t.Fatalf("Failed to record payment: %v", err)
	}

	// Small delay to ensure different timestamps
	time.Sleep(10 * time.Millisecond)

	// Record another payment
	if err := db.RecordPayment(pubkey, 20000, "lnbc200...", "preimage456"); err != nil {
		t.Fatalf("Failed to record payment: %v", err)
	}

	// Check payment history
	payments, err = db.GetPaymentHistory(pubkey)
	if err != nil {
		t.Fatalf("Failed to get payment history: %v", err)
	}
	if len(payments) != 2 {
		t.Errorf("Expected 2 payments, got %d", len(payments))
	}

	t.Logf("Retrieved %d payments from history", len(payments))
}

// TestIsFirstTimeUser tests first-time user detection
func TestIsFirstTimeUser(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	pubkey := make([]byte, 32)
	for i := range pubkey {
		pubkey[i] = byte(i + 90)
	}

	// First check should be true
	isFirst, err := db.IsFirstTimeUser(pubkey)
	if err != nil {
		t.Fatalf("Failed to check first time user: %v", err)
	}
	if !isFirst {
		t.Error("Expected true for first check")
	}

	// Second check should be false
	isFirst, err = db.IsFirstTimeUser(pubkey)
	if err != nil {
		t.Fatalf("Failed to check first time user: %v", err)
	}
	if isFirst {
		t.Error("Expected false for second check")
	}

	t.Log("First time user detection test passed")
}

// TestSubscriptionInvalidDays tests that invalid day counts are rejected
func TestSubscriptionInvalidDays(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	pubkey := make([]byte, 32)

	// Try to extend with 0 days
	err = db.ExtendSubscription(pubkey, 0)
	if err == nil {
		t.Error("Expected error for 0 days")
	}

	// Try to extend with negative days
	err = db.ExtendSubscription(pubkey, -5)
	if err == nil {
		t.Error("Expected error for negative days")
	}

	t.Log("Invalid days correctly rejected")
}

// ============================================================================
// Import/Export Tests
// ============================================================================

// TestImportExport tests basic import/export functionality
func TestImportExport(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create and save some events
	for i := 0; i < 3; i++ {
		ev := createTestEvent(1, "Export test event", nil)
		ev.ID[0] = byte(0xAA + i)
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Export to buffer
	var exportBuf bytes.Buffer
	db.Export(ctx, &exportBuf)

	exportData := exportBuf.String()
	if len(exportData) == 0 {
		t.Error("Expected non-empty export data")
	}

	// Count lines (should be 3 JSONL lines)
	lines := bytes.Count(exportBuf.Bytes(), []byte("\n"))
	if lines != 3 {
		t.Errorf("Expected 3 export lines, got %d", lines)
	}

	t.Logf("Exported %d events to %d bytes", lines, len(exportData))
}

// TestImportFromReader tests importing events from JSONL reader
func TestImportFromReader(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create JSONL import data
	// Note: These are simplified test events - real events would have valid signatures
	jsonl := `{"id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","pubkey":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","created_at":1700000000,"kind":1,"tags":[],"content":"Test event 1","sig":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"}
{"id":"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd","pubkey":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","created_at":1700000001,"kind":1,"tags":[],"content":"Test event 2","sig":"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"}
`

	reader := bytes.NewReader([]byte(jsonl))
	err = db.ImportEventsFromReader(ctx, reader)
	if err != nil {
		t.Fatalf("Failed to import events: %v", err)
	}

	t.Log("Import from reader test completed")
}

// TestImportExportRoundTrip tests full round-trip import/export
func TestImportExportRoundTrip(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Create first database
	db1, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database 1: %v", err)
	}
	defer db1.Close()

	<-db1.Ready()

	// Wipe to ensure clean state
	if err := db1.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create events with specific content for verification
	// Using kinds 1, 7, 10, 20, 30 to avoid kind 3 which requires p tags
	kinds := []uint16{1, 7, 10, 20, 30}
	originalEvents := make([]*event.E, 5)
	for i := 0; i < 5; i++ {
		ev := createTestEvent(kinds[i], "Round trip content "+string(rune('A'+i)), nil)
		ev.ID[0] = byte(0xBB + i)
		originalEvents[i] = ev
		if _, err := db1.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Export from db1
	var exportBuf bytes.Buffer
	db1.Export(ctx, &exportBuf)

	// Wipe db1 (simulating a fresh database)
	if err := db1.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Import back
	db1.Import(&exportBuf)

	// Query all events
	f := &filter.F{}
	evs, err := db1.QueryEvents(ctx, f)
	if err != nil {
		t.Fatalf("Failed to query events: %v", err)
	}

	if len(evs) < 5 {
		t.Errorf("Expected at least 5 events after round trip, got %d", len(evs))
	}

	t.Logf("Round trip test: %d events survived", len(evs))
}

// TestGetSerialsByPubkey tests retrieving serials by pubkey
func TestGetSerialsByPubkey(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create a specific author
	author := make([]byte, 32)
	for i := range author {
		author[i] = 0xCC
	}

	// Create events from this author
	for i := 0; i < 3; i++ {
		ev := createTestEvent(1, "Author test", author)
		ev.ID[0] = byte(0xCC + i)
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Get serials by pubkey
	serials, err := db.GetSerialsByPubkey(author)
	if err != nil {
		t.Fatalf("Failed to get serials by pubkey: %v", err)
	}

	if len(serials) != 3 {
		t.Errorf("Expected 3 serials, got %d", len(serials))
	}

	t.Logf("GetSerialsByPubkey returned %d serials", len(serials))
}

// TestExportByPubkey tests exporting events filtered by pubkey
func TestExportByPubkey(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	db, err := New(ctx, cancel, "/tmp/test", "info")
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer db.Close()

	<-db.Ready()

	// Wipe to ensure clean state
	if err := db.Wipe(); err != nil {
		t.Fatalf("Failed to wipe database: %v", err)
	}

	// Create two different authors
	author1 := make([]byte, 32)
	for i := range author1 {
		author1[i] = 0xDD
	}
	author2 := make([]byte, 32)
	for i := range author2 {
		author2[i] = 0xEE
	}

	// Create events from both authors
	for i := 0; i < 2; i++ {
		ev := createTestEvent(1, "Author 1 content", author1)
		ev.ID[0] = byte(0xD0 + i)
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}
	for i := 0; i < 3; i++ {
		ev := createTestEvent(1, "Author 2 content", author2)
		ev.ID[0] = byte(0xE0 + i)
		if _, err := db.SaveEvent(ctx, ev); err != nil {
			t.Fatalf("Failed to save event: %v", err)
		}
	}

	// Export only author1's events
	var exportBuf bytes.Buffer
	db.Export(ctx, &exportBuf, author1)

	lines := bytes.Count(exportBuf.Bytes(), []byte("\n"))
	if lines != 2 {
		t.Errorf("Expected 2 export lines for author1, got %d", lines)
	}

	t.Logf("Exported %d events for specific pubkey", lines)
}

