package websocketspec

import (
	"context"
	"encoding/json"
	"testing"

	"github.com/bitechdev/ResolveSpec/pkg/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
)

// MockDatabase is a mock implementation of common.Database for testing
type MockDatabase struct {
	mock.Mock
}

func (m *MockDatabase) NewSelect() common.SelectQuery {
	args := m.Called()
	return args.Get(0).(common.SelectQuery)
}

func (m *MockDatabase) NewInsert() common.InsertQuery {
	args := m.Called()
	return args.Get(0).(common.InsertQuery)
}

func (m *MockDatabase) NewUpdate() common.UpdateQuery {
	args := m.Called()
	return args.Get(0).(common.UpdateQuery)
}

func (m *MockDatabase) NewDelete() common.DeleteQuery {
	args := m.Called()
	return args.Get(0).(common.DeleteQuery)
}

func (m *MockDatabase) Close() error {
	args := m.Called()
	return args.Error(0)
}

func (m *MockDatabase) Exec(ctx context.Context, query string, args ...interface{}) (common.Result, error) {
	callArgs := m.Called(ctx, query, args)
	if callArgs.Get(0) == nil {
		return nil, callArgs.Error(1)
	}
	return callArgs.Get(0).(common.Result), callArgs.Error(1)
}

func (m *MockDatabase) Query(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
	callArgs := m.Called(ctx, dest, query, args)
	return callArgs.Error(0)
}

func (m *MockDatabase) BeginTx(ctx context.Context) (common.Database, error) {
	args := m.Called(ctx)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(common.Database), args.Error(1)
}

func (m *MockDatabase) CommitTx(ctx context.Context) error {
	args := m.Called(ctx)
	return args.Error(0)
}

func (m *MockDatabase) RollbackTx(ctx context.Context) error {
	args := m.Called(ctx)
	return args.Error(0)
}

func (m *MockDatabase) RunInTransaction(ctx context.Context, fn func(common.Database) error) error {
	args := m.Called(ctx, fn)
	return args.Error(0)
}

func (m *MockDatabase) GetUnderlyingDB() interface{} {
	args := m.Called()
	return args.Get(0)
}

func (m *MockDatabase) DriverName() string {
	return "postgres"
}

// MockSelectQuery is a mock implementation of common.SelectQuery
type MockSelectQuery struct {
	mock.Mock
}

func (m *MockSelectQuery) Model(model interface{}) common.SelectQuery {
	args := m.Called(model)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Table(table string) common.SelectQuery {
	args := m.Called(table)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Column(columns ...string) common.SelectQuery {
	args := m.Called(columns)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Where(query string, args ...interface{}) common.SelectQuery {
	callArgs := m.Called(query, args)
	return callArgs.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) WhereIn(column string, values interface{}) common.SelectQuery {
	args := m.Called(column, values)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Order(order string) common.SelectQuery {
	args := m.Called(order)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Limit(limit int) common.SelectQuery {
	args := m.Called(limit)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Offset(offset int) common.SelectQuery {
	args := m.Called(offset)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) PreloadRelation(relation string, apply ...func(common.SelectQuery) common.SelectQuery) common.SelectQuery {
	args := m.Called(relation, apply)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Preload(relation string, conditions ...interface{}) common.SelectQuery {
	args := m.Called(relation, conditions)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) ColumnExpr(query string, args ...interface{}) common.SelectQuery {
	callArgs := m.Called(query, args)
	return callArgs.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) WhereOr(query string, args ...interface{}) common.SelectQuery {
	callArgs := m.Called(query, args)
	return callArgs.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Join(query string, args ...interface{}) common.SelectQuery {
	callArgs := m.Called(query, args)
	return callArgs.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) LeftJoin(query string, args ...interface{}) common.SelectQuery {
	callArgs := m.Called(query, args)
	return callArgs.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) JoinRelation(relation string, apply ...func(common.SelectQuery) common.SelectQuery) common.SelectQuery {
	args := m.Called(relation, apply)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) OrderExpr(order string, args ...interface{}) common.SelectQuery {
	callArgs := m.Called(order, args)
	return callArgs.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Group(group string) common.SelectQuery {
	args := m.Called(group)
	return args.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Having(having string, args ...interface{}) common.SelectQuery {
	callArgs := m.Called(having, args)
	return callArgs.Get(0).(common.SelectQuery)
}

func (m *MockSelectQuery) Scan(ctx context.Context, dest interface{}) error {
	args := m.Called(ctx, dest)
	return args.Error(0)
}

func (m *MockSelectQuery) ScanModel(ctx context.Context) error {
	args := m.Called(ctx)
	return args.Error(0)
}

func (m *MockSelectQuery) Count(ctx context.Context) (int, error) {
	args := m.Called(ctx)
	return args.Int(0), args.Error(1)
}

func (m *MockSelectQuery) Exists(ctx context.Context) (bool, error) {
	args := m.Called(ctx)
	return args.Bool(0), args.Error(1)
}

// MockInsertQuery is a mock implementation of common.InsertQuery
type MockInsertQuery struct {
	mock.Mock
}

func (m *MockInsertQuery) Model(model interface{}) common.InsertQuery {
	args := m.Called(model)
	return args.Get(0).(common.InsertQuery)
}

func (m *MockInsertQuery) Table(table string) common.InsertQuery {
	args := m.Called(table)
	return args.Get(0).(common.InsertQuery)
}

func (m *MockInsertQuery) Value(column string, value interface{}) common.InsertQuery {
	args := m.Called(column, value)
	return args.Get(0).(common.InsertQuery)
}

func (m *MockInsertQuery) OnConflict(action string) common.InsertQuery {
	args := m.Called(action)
	return args.Get(0).(common.InsertQuery)
}

func (m *MockInsertQuery) Returning(columns ...string) common.InsertQuery {
	args := m.Called(columns)
	return args.Get(0).(common.InsertQuery)
}

func (m *MockInsertQuery) Exec(ctx context.Context) (common.Result, error) {
	args := m.Called(ctx)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(common.Result), args.Error(1)
}

func (m *MockInsertQuery) Scan(ctx context.Context, dest interface{}) error {
	args := m.Called(ctx, dest)
	return args.Error(0)
}

// MockUpdateQuery is a mock implementation of common.UpdateQuery
type MockUpdateQuery struct {
	mock.Mock
}

func (m *MockUpdateQuery) Model(model interface{}) common.UpdateQuery {
	args := m.Called(model)
	return args.Get(0).(common.UpdateQuery)
}

func (m *MockUpdateQuery) Table(table string) common.UpdateQuery {
	args := m.Called(table)
	return args.Get(0).(common.UpdateQuery)
}

func (m *MockUpdateQuery) Set(column string, value interface{}) common.UpdateQuery {
	args := m.Called(column, value)
	return args.Get(0).(common.UpdateQuery)
}

func (m *MockUpdateQuery) SetMap(values map[string]interface{}) common.UpdateQuery {
	args := m.Called(values)
	return args.Get(0).(common.UpdateQuery)
}

func (m *MockUpdateQuery) Where(query string, args ...interface{}) common.UpdateQuery {
	callArgs := m.Called(query, args)
	return callArgs.Get(0).(common.UpdateQuery)
}

func (m *MockUpdateQuery) Exec(ctx context.Context) (common.Result, error) {
	args := m.Called(ctx)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(common.Result), args.Error(1)
}

// MockDeleteQuery is a mock implementation of common.DeleteQuery
type MockDeleteQuery struct {
	mock.Mock
}

func (m *MockDeleteQuery) Model(model interface{}) common.DeleteQuery {
	args := m.Called(model)
	return args.Get(0).(common.DeleteQuery)
}

func (m *MockDeleteQuery) Table(table string) common.DeleteQuery {
	args := m.Called(table)
	return args.Get(0).(common.DeleteQuery)
}

func (m *MockDeleteQuery) Where(query string, args ...interface{}) common.DeleteQuery {
	callArgs := m.Called(query, args)
	return callArgs.Get(0).(common.DeleteQuery)
}

func (m *MockDeleteQuery) Exec(ctx context.Context) (common.Result, error) {
	args := m.Called(ctx)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(common.Result), args.Error(1)
}

// MockModelRegistry is a mock implementation of common.ModelRegistry
type MockModelRegistry struct {
	mock.Mock
}

func (m *MockModelRegistry) RegisterModel(key string, model interface{}) error {
	args := m.Called(key, model)
	return args.Error(0)
}

func (m *MockModelRegistry) GetModel(key string) (interface{}, error) {
	args := m.Called(key)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0), args.Error(1)
}

func (m *MockModelRegistry) GetAllModels() map[string]interface{} {
	args := m.Called()
	return args.Get(0).(map[string]interface{})
}

func (m *MockModelRegistry) GetModelByEntity(schema, entity string) (interface{}, error) {
	args := m.Called(schema, entity)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0), args.Error(1)
}

// Test model
type TestUser struct {
	ID     uint   `json:"id" gorm:"primaryKey"`
	Name   string `json:"name"`
	Email  string `json:"email"`
	Status string `json:"status"`
}

func TestNewHandler(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}

	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	assert.NotNil(t, handler)
	assert.NotNil(t, handler.db)
	assert.NotNil(t, handler.registry)
	assert.NotNil(t, handler.hooks)
	assert.NotNil(t, handler.connManager)
	assert.NotNil(t, handler.subscriptionManager)
	assert.NotNil(t, handler.upgrader)
}

func TestHandler_Hooks(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	hooks := handler.Hooks()
	assert.NotNil(t, hooks)
	assert.IsType(t, &HookRegistry{}, hooks)
}

func TestHandler_Registry(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	registry := handler.Registry()
	assert.NotNil(t, registry)
	assert.Equal(t, mockRegistry, registry)
}

func TestHandler_GetDatabase(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	db := handler.GetDatabase()
	assert.NotNil(t, db)
	assert.Equal(t, mockDB, db)
}

func TestHandler_GetConnectionCount(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	count := handler.GetConnectionCount()
	assert.Equal(t, 0, count)
}

func TestHandler_GetSubscriptionCount(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	count := handler.GetSubscriptionCount()
	assert.Equal(t, 0, count)
}

func TestHandler_GetConnection(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	// Non-existent connection
	_, exists := handler.GetConnection("non-existent")
	assert.False(t, exists)
}

func TestHandler_HandleMessage_InvalidType(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	conn := &Connection{
		ID:            "conn-1",
		send:          make(chan []byte, 256),
		subscriptions: make(map[string]*Subscription),
		ctx:           context.Background(),
	}

	msg := &Message{
		ID:   "msg-1",
		Type: MessageType("invalid"),
	}

	handler.HandleMessage(conn, msg)

	// Shutdown handler properly
	defer handler.Shutdown()

	// Should send error response
	select {
	case data := <-conn.send:
		var response ResponseMessage
		err := json.Unmarshal(data, &response)
		require.NoError(t, err)
		assert.False(t, response.Success)
		assert.NotNil(t, response.Error)
	default:
		t.Fatal("Expected error response")
	}
}

func TestHandler_GetOperatorSQL(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	tests := []struct {
		operator string
		expected string
	}{
		{"eq", "="},
		{"neq", "!="},
		{"gt", ">"},
		{"gte", ">="},
		{"lt", "<"},
		{"lte", "<="},
		{"like", "LIKE"},
		{"ilike", "ILIKE"},
		{"in", "IN"},
		{"unknown", "="}, // default
	}

	for _, tt := range tests {
		t.Run(tt.operator, func(t *testing.T) {
			result := handler.getOperatorSQL(tt.operator)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestHandler_GetTableName(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	tests := []struct {
		name     string
		schema   string
		entity   string
		expected string
	}{
		{
			name:     "With schema",
			schema:   "public",
			entity:   "users",
			expected: "public.users",
		},
		{
			name:     "Without schema",
			schema:   "",
			entity:   "users",
			expected: "users",
		},
		{
			name:     "Different schema",
			schema:   "custom",
			entity:   "posts",
			expected: "custom.posts",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := handler.getTableName(tt.schema, tt.entity, &TestUser{})
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestHandler_GetMetadata(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	metadata := handler.getMetadata("public", "users", &TestUser{})

	assert.NotNil(t, metadata)
	assert.Equal(t, "public", metadata["schema"])
	assert.Equal(t, "users", metadata["entity"])
	assert.Equal(t, "public.users", metadata["table_name"])
	assert.NotNil(t, metadata["columns"])
	assert.NotNil(t, metadata["primary_key"])
}

func TestHandler_NotifySubscribers(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	// Create connection
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	conn := &Connection{
		ID:            "conn-1",
		send:          make(chan []byte, 256),
		subscriptions: make(map[string]*Subscription),
		handler:       handler,
		ctx:           ctx,
		cancel:        cancel,
	}

	// Register connection
	handler.connManager.connections["conn-1"] = conn

	// Create subscription
	sub := handler.subscriptionManager.Subscribe("sub-1", "conn-1", "public", "users", nil)
	conn.AddSubscription(sub)

	// Notify subscribers
	data := map[string]interface{}{"id": 1, "name": "John"}
	handler.notifySubscribers("public", "users", OperationCreate, data)

	// Verify notification was sent
	select {
	case msg := <-conn.send:
		assert.NotEmpty(t, msg)
	default:
		t.Fatal("Expected notification to be sent")
	}
}

func TestHandler_NotifySubscribers_NoSubscribers(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	// Notify with no subscribers - should not panic
	data := map[string]interface{}{"id": 1, "name": "John"}
	handler.notifySubscribers("public", "users", OperationCreate, data)

	// No assertions needed - just checking it doesn't panic
}

func TestHandler_NotifySubscribers_ConnectionNotFound(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	// Create subscription without connection
	handler.subscriptionManager.Subscribe("sub-1", "conn-1", "public", "users", nil)

	// Notify - should handle gracefully when connection not found
	data := map[string]interface{}{"id": 1, "name": "John"}
	handler.notifySubscribers("public", "users", OperationCreate, data)

	// No assertions needed - just checking it doesn't panic
}

func TestHandler_HooksIntegration(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	beforeCalled := false
	afterCalled := false

	// Register hooks
	handler.Hooks().RegisterBefore(OperationCreate, func(ctx *HookContext) error {
		beforeCalled = true
		return nil
	})

	handler.Hooks().RegisterAfter(OperationCreate, func(ctx *HookContext) error {
		afterCalled = true
		return nil
	})

	// Verify hooks are registered
	assert.True(t, handler.Hooks().HasHooks(BeforeCreate))
	assert.True(t, handler.Hooks().HasHooks(AfterCreate))

	// Execute hooks
	ctx := &HookContext{Context: context.Background()}
	handler.Hooks().Execute(BeforeCreate, ctx)
	handler.Hooks().Execute(AfterCreate, ctx)

	assert.True(t, beforeCalled)
	assert.True(t, afterCalled)
}

func TestHandler_Shutdown(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	// Shutdown should not panic
	handler.Shutdown()

	// Verify context was cancelled
	select {
	case <-handler.connManager.ctx.Done():
		// Expected
	default:
		t.Fatal("Connection manager context not cancelled after shutdown")
	}
}

func TestHandler_SubscriptionLifecycle(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	// Create connection
	conn := &Connection{
		ID:            "conn-1",
		send:          make(chan []byte, 256),
		subscriptions: make(map[string]*Subscription),
		ctx:           context.Background(),
		handler:       handler,
	}

	// Create subscription message
	msg := &Message{
		ID:        "sub-msg-1",
		Type:      MessageTypeSubscription,
		Operation: OperationSubscribe,
		Schema:    "public",
		Entity:    "users",
	}

	// Handle subscribe
	handler.handleSubscribe(conn, msg)

	// Verify subscription was created
	assert.Equal(t, 1, handler.GetSubscriptionCount())
	assert.Equal(t, 1, len(conn.subscriptions))

	// Verify response was sent
	select {
	case data := <-conn.send:
		assert.NotEmpty(t, data)
	default:
		t.Fatal("Expected subscription response")
	}
}

func TestHandler_UnsubscribeLifecycle(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	// Create connection
	conn := &Connection{
		ID:            "conn-1",
		send:          make(chan []byte, 256),
		subscriptions: make(map[string]*Subscription),
		ctx:           context.Background(),
		handler:       handler,
	}

	// Create subscription
	sub := handler.subscriptionManager.Subscribe("sub-1", "conn-1", "public", "users", nil)
	conn.AddSubscription(sub)

	assert.Equal(t, 1, handler.GetSubscriptionCount())

	// Create unsubscribe message
	msg := &Message{
		ID:             "unsub-msg-1",
		Type:           MessageTypeSubscription,
		Operation:      OperationUnsubscribe,
		SubscriptionID: "sub-1",
	}

	// Handle unsubscribe
	handler.handleUnsubscribe(conn, msg)

	// Verify subscription was removed
	assert.Equal(t, 0, handler.GetSubscriptionCount())
	assert.Equal(t, 0, len(conn.subscriptions))

	// Verify response was sent
	select {
	case data := <-conn.send:
		assert.NotEmpty(t, data)
	default:
		t.Fatal("Expected unsubscribe response")
	}
}

func TestHandler_HandlePing(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	conn := &Connection{
		ID:            "conn-1",
		send:          make(chan []byte, 256),
		subscriptions: make(map[string]*Subscription),
		ctx:           ctx,
		cancel:        cancel,
	}

	msg := &Message{
		ID:   "ping-1",
		Type: MessageTypePing,
	}

	handler.handlePing(conn, msg)

	// Verify pong was sent
	select {
	case data := <-conn.send:
		assert.NotEmpty(t, data)
	default:
		t.Fatal("Expected pong response")
	}
}

func TestHandler_CompleteWorkflow(t *testing.T) {
	mockDB := &MockDatabase{}
	mockRegistry := &MockModelRegistry{}
	handler := NewHandler(mockDB, mockRegistry)
	defer handler.Shutdown()

	// Setup hooks (these are registered but not called in this test workflow)
	handler.Hooks().RegisterBefore(OperationCreate, func(ctx *HookContext) error {
		return nil
	})

	handler.Hooks().RegisterAfter(OperationCreate, func(ctx *HookContext) error {
		return nil
	})

	// Create connection
	conn := &Connection{
		ID:            "conn-1",
		send:          make(chan []byte, 256),
		subscriptions: make(map[string]*Subscription),
		ctx:           context.Background(),
		handler:       handler,
		metadata:      make(map[string]interface{}),
	}

	// Register connection
	handler.connManager.connections["conn-1"] = conn

	// Set user metadata
	conn.SetMetadata("user_id", 123)

	// Create subscription
	subMsg := &Message{
		ID:        "sub-1",
		Type:      MessageTypeSubscription,
		Operation: OperationSubscribe,
		Schema:    "public",
		Entity:    "users",
	}

	handler.handleSubscribe(conn, subMsg)
	assert.Equal(t, 1, handler.GetSubscriptionCount())

	// Clear send channel
	select {
	case <-conn.send:
	default:
	}

	// Send ping
	pingMsg := &Message{
		ID:   "ping-1",
		Type: MessageTypePing,
	}

	handler.handlePing(conn, pingMsg)

	// Verify pong was sent
	select {
	case <-conn.send:
		// Expected
	default:
		t.Fatal("Expected pong response")
	}

	// Verify metadata
	userID, exists := conn.GetMetadata("user_id")
	assert.True(t, exists)
	assert.Equal(t, 123, userID)

	// Verify hooks were registered
	assert.True(t, handler.Hooks().HasHooks(BeforeCreate))
	assert.True(t, handler.Hooks().HasHooks(AfterCreate))
}
