package rest

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

	"github.com/gin-gonic/gin"
	"github.com/nexuscrm/backend/internal/features/streaming"
)

func TestNewWebSocketHandler(t *testing.T) {
	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)
	if handler == nil {
		t.Error("Expected non-nil handler")
	}
}

func TestCheckWebSocketOrigin_AllowLocalhost(t *testing.T) {
	t.Setenv("FRONTEND_URL", "http://127.0.0.1:4173")
	t.Setenv("CORS_ALLOWED_ORIGINS", "")
	t.Setenv("ALLOWED_ORIGINS", "")
	req := httptest.NewRequest("GET", "/ws", nil)
	req.Header.Set("Origin", "http://127.0.0.1:4173")

	if !checkWebSocketOrigin(req) {
		t.Error("Expected FRONTEND_URL origin to be allowed")
	}
}

func TestCheckWebSocketOrigin_NoOrigin(t *testing.T) {
	req := httptest.NewRequest("GET", "/ws", nil)
	// No Origin header

	if !checkWebSocketOrigin(req) {
		t.Error("Expected request without Origin to be allowed")
	}
}

func TestCheckWebSocketOrigin_RejectUnknown(t *testing.T) {
	req := httptest.NewRequest("GET", "/ws", nil)
	req.Header.Set("Origin", "http://evil.com")

	if checkWebSocketOrigin(req) {
		t.Error("Expected evil.com to be rejected")
	}
}

func TestWebSocketHandler_HandleConnection_RequiresUpgrade(t *testing.T) {
	gin.SetMode(gin.TestMode)

	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)

	router := gin.New()
	router.GET("/ws", handler.HandleConnection)

	// Regular HTTP request (not WebSocket upgrade)
	req := httptest.NewRequest("GET", "/ws", nil)
	w := httptest.NewRecorder()

	router.ServeHTTP(w, req)

	// Should fail because it's not a WebSocket upgrade request
	if w.Code == http.StatusSwitchingProtocols {
		t.Error("Should not upgrade non-WebSocket request")
	}
}

func TestClientCount(t *testing.T) {
	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)

	if handler.ClientCount() != 0 {
		t.Errorf("Expected 0 clients, got %d", handler.ClientCount())
	}
}

func TestSendToClient_NonExistent(t *testing.T) {
	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)

	// Should not panic for non-existent client
	err := handler.sendToClient("non-existent", map[string]string{"test": "data"})
	if err != nil {
		t.Errorf("Expected nil error for non-existent client, got %v", err)
	}
}

func TestBroadcast_NoClients(t *testing.T) {
	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)

	// Should not panic with no clients
	handler.Broadcast("/topic/test", map[string]string{"test": "data"})
}

func TestCheckWebSocketOrigin_CustomAllowed(t *testing.T) {
	// Set custom allowed origins
	t.Setenv("FRONTEND_URL", "http://127.0.0.1:4173")
	t.Setenv("CORS_ALLOWED_ORIGINS", "http://custom.com,http://another.com")
	t.Setenv("ALLOWED_ORIGINS", "")

	req := httptest.NewRequest("GET", "/ws", nil)
	req.Header.Set("Origin", "http://custom.com")

	if !checkWebSocketOrigin(req) {
		t.Error("Expected custom.com to be allowed")
	}
}

func TestWsClient_WriteJSON(t *testing.T) {
	// Cannot easily test without actual WebSocket connection
	// This is a structural test to ensure wsClient exists
	client := &wsClient{}
	if client.conn != nil {
		t.Error("Expected nil conn for uninitialized client")
	}
}

func TestHandleMessage_InvalidJSON(t *testing.T) {
	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)
	clientID := sm.CreateSession()

	// Should not panic on invalid JSON
	handler.handleMessage(clientID, []byte("not json"))
}

func TestHandleMessage_Subscribe(t *testing.T) {
	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)
	clientID := sm.CreateSession()

	// Create valid subscribe message
	msg := `{"channel":"/meta/subscribe","subscription":"/topic/test"}`
	handler.handleMessage(clientID, []byte(msg))

	// Check subscription was added
	channels := sm.GetSubscribedChannels(clientID)
	found := false
	for _, ch := range channels {
		if ch == "/topic/test" {
			found = true
			break
		}
	}

	if !found {
		t.Error("Expected subscription to be added")
	}
}

func TestHandleMessage_Unsubscribe(t *testing.T) {
	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)
	clientID := sm.CreateSession()

	// Subscribe first
	sm.Subscribe(clientID, "/topic/test")

	// Unsubscribe
	msg := `{"channel":"/meta/unsubscribe","subscription":"/topic/test"}`
	handler.handleMessage(clientID, []byte(msg))

	channels := sm.GetSubscribedChannels(clientID)
	for _, ch := range channels {
		if ch == "/topic/test" {
			t.Error("Expected subscription to be removed")
		}
	}
}

func TestUpgrader_CheckOrigin(t *testing.T) {
	// Verify upgrader uses our checkWebSocketOrigin
	if upgrader.CheckOrigin == nil {
		t.Error("Expected CheckOrigin to be set")
	}
}

func TestCheckWebSocketOrigin_127(t *testing.T) {
	t.Setenv("FRONTEND_URL", "")
	t.Setenv("CORS_ALLOWED_ORIGINS", "")
	t.Setenv("ALLOWED_ORIGINS", "http://127.0.0.1:5173")
	req := httptest.NewRequest("GET", "/ws", nil)
	req.Header.Set("Origin", "http://127.0.0.1:5173")

	if !checkWebSocketOrigin(req) {
		t.Error("Expected 127.0.0.1:5173 to be allowed")
	}
}

func TestHandleMessage_Disconnect(t *testing.T) {
	sm := streaming.NewSessionManager(30 * 60)
	defer sm.Stop()

	handler := NewWebSocketHandler(nil, sm)
	clientID := sm.CreateSession()

	// Disconnect message (handler will try to send response, which will fail silently)
	msg := `{"channel":"/meta/disconnect"}`
	handler.handleMessage(clientID, []byte(msg))

	// Session should still exist (cleanup happens on connection close)
	if !sm.ValidateSession(clientID) {
		t.Error("Session should still exist after disconnect message")
	}
}
