package handlers

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"veza-backend-api/internal/logging"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
)

func TestFrontendLogHandler_ReceiveLog_Success(t *testing.T) {
	// Setup
	gin.SetMode(gin.TestMode)
	router := gin.New()

	logger := zap.NewNop()
	frontendLogger, _ := logging.NewLoggerWithFileRotation("./test_logs", "frontend", "test", "info")
	handler := &FrontendLogHandler{
		logger:         logger,
		frontendLogger: frontendLogger,
		logDir:         "./test_logs",
		commonHandler:  NewCommonHandler(logger),
	}

	router.POST("/api/v1/logs/frontend", handler.ReceiveLog)

	reqBody := FrontendLogRequest{
		Timestamp: "2024-01-01T00:00:00Z",
		Level:     "INFO",
		Message:   "Test log message",
		Context:   map[string]interface{}{"request_id": "test-123"},
	}

	body, _ := json.Marshal(reqBody)

	// Execute
	req, _ := http.NewRequest("POST", "/api/v1/logs/frontend", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Assert
	assert.Equal(t, http.StatusOK, w.Code)

	var response map[string]interface{}
	err := json.Unmarshal(w.Body.Bytes(), &response)
	assert.NoError(t, err)
	assert.True(t, response["success"].(bool))
}

func TestFrontendLogHandler_ReceiveLog_InvalidJSON(t *testing.T) {
	// Setup
	gin.SetMode(gin.TestMode)
	router := gin.New()

	logger := zap.NewNop()
	frontendLogger, _ := logging.NewLoggerWithFileRotation("./test_logs", "frontend", "test", "info")
	handler := &FrontendLogHandler{
		logger:         logger,
		frontendLogger: frontendLogger,
		logDir:         "./test_logs",
		commonHandler:  NewCommonHandler(logger),
	}

	router.POST("/api/v1/logs/frontend", handler.ReceiveLog)

	// Execute - Invalid JSON
	req, _ := http.NewRequest("POST", "/api/v1/logs/frontend", bytes.NewBuffer([]byte("invalid json")))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Assert
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestFrontendLogHandler_ReceiveLog_DefaultLevel(t *testing.T) {
	// Setup
	gin.SetMode(gin.TestMode)
	router := gin.New()

	logger := zap.NewNop()
	frontendLogger, _ := logging.NewLoggerWithFileRotation("./test_logs", "frontend", "test", "info")
	handler := &FrontendLogHandler{
		logger:         logger,
		frontendLogger: frontendLogger,
		logDir:         "./test_logs",
		commonHandler:  NewCommonHandler(logger),
	}

	router.POST("/api/v1/logs/frontend", handler.ReceiveLog)

	reqBody := FrontendLogRequest{
		Timestamp: "2024-01-01T00:00:00Z",
		Level:     "", // Empty level should default to INFO
		Message:   "Test log message",
	}

	body, _ := json.Marshal(reqBody)

	// Execute
	req, _ := http.NewRequest("POST", "/api/v1/logs/frontend", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Assert
	assert.Equal(t, http.StatusOK, w.Code)

	var response map[string]interface{}
	err := json.Unmarshal(w.Body.Bytes(), &response)
	assert.NoError(t, err)

	data := response["data"].(map[string]interface{})
	assert.Equal(t, "INFO", data["level"])
}

func TestFrontendLogHandler_ReceiveLog_DifferentLevels(t *testing.T) {
	// Setup
	gin.SetMode(gin.TestMode)
	router := gin.New()

	logger := zap.NewNop()
	frontendLogger, _ := logging.NewLoggerWithFileRotation("./test_logs", "frontend", "test", "info")
	handler := &FrontendLogHandler{
		logger:         logger,
		frontendLogger: frontendLogger,
		logDir:         "./test_logs",
		commonHandler:  NewCommonHandler(logger),
	}

	router.POST("/api/v1/logs/frontend", handler.ReceiveLog)

	levels := []string{"DEBUG", "INFO", "WARN", "ERROR", "UNKNOWN"}

	for _, level := range levels {
		reqBody := FrontendLogRequest{
			Timestamp: "2024-01-01T00:00:00Z",
			Level:     level,
			Message:   "Test log message",
		}

		body, _ := json.Marshal(reqBody)

		// Execute
		req, _ := http.NewRequest("POST", "/api/v1/logs/frontend", bytes.NewBuffer(body))
		req.Header.Set("Content-Type", "application/json")
		w := httptest.NewRecorder()
		router.ServeHTTP(w, req)

		// Assert
		assert.Equal(t, http.StatusOK, w.Code, "Level: %s", level)
	}
}

func TestFrontendLogHandler_ReceiveLog_WithContext(t *testing.T) {
	// Setup
	gin.SetMode(gin.TestMode)
	router := gin.New()

	logger := zap.NewNop()
	frontendLogger, _ := logging.NewLoggerWithFileRotation("./test_logs", "frontend", "test", "info")
	handler := &FrontendLogHandler{
		logger:         logger,
		frontendLogger: frontendLogger,
		logDir:         "./test_logs",
		commonHandler:  NewCommonHandler(logger),
	}

	router.POST("/api/v1/logs/frontend", handler.ReceiveLog)

	reqBody := FrontendLogRequest{
		Timestamp: "2024-01-01T00:00:00Z",
		Level:     "INFO",
		Message:   "Test log message",
		Context: map[string]interface{}{
			"request_id": "test-123",
			"user_id":    "user-456",
			"action":     "test_action",
		},
		Data: map[string]interface{}{
			"key": "value",
		},
	}

	body, _ := json.Marshal(reqBody)

	// Execute
	req, _ := http.NewRequest("POST", "/api/v1/logs/frontend", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Assert
	assert.Equal(t, http.StatusOK, w.Code)
}
