package handlers

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

	"veza-backend-api/internal/metrics"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
)

// MockErrorMetrics mocks ErrorMetrics for testing
type MockErrorMetrics struct {
	aggregatedMetrics *metrics.AggregatedMetrics
}

func (m *MockErrorMetrics) GetAggregatedMetrics() *metrics.AggregatedMetrics {
	return m.aggregatedMetrics
}

func setupTestAggregatedMetricsRouter(mockMetrics *MockErrorMetrics) *gin.Engine {
	gin.SetMode(gin.TestMode)
	router := gin.New()

	handler := NewAggregatedMetricsHandlerWithInterface(mockMetrics)
	router.GET("/metrics/aggregated", handler.GetAggregated)

	return router
}

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

	mockMetrics := &MockErrorMetrics{
		aggregatedMetrics: &metrics.AggregatedMetrics{},
	}
	handler := NewAggregatedMetricsHandlerWithInterface(mockMetrics)
	router.GET("/metrics/aggregated", handler.GetAggregated)

	// Execute - No window parameter
	req, _ := http.NewRequest("GET", "/metrics/aggregated", nil)
	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.Contains(t, response, "windows")
}

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

	mockMetrics := &MockErrorMetrics{
		aggregatedMetrics: &metrics.AggregatedMetrics{},
	}
	handler := NewAggregatedMetricsHandlerWithInterface(mockMetrics)
	router.GET("/metrics/aggregated", handler.GetAggregated)

	validWindows := []string{"1m", "5m", "1h"}

	for _, window := range validWindows {
		// Execute
		req, _ := http.NewRequest("GET", "/metrics/aggregated?window="+window, nil)
		w := httptest.NewRecorder()
		router.ServeHTTP(w, req)

		// Assert
		assert.Equal(t, http.StatusOK, w.Code, "Window: %s", window)

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

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

	mockMetrics := &MockErrorMetrics{
		aggregatedMetrics: &metrics.AggregatedMetrics{},
	}
	handler := NewAggregatedMetricsHandlerWithInterface(mockMetrics)
	router.GET("/metrics/aggregated", handler.GetAggregated)

	// Execute - Invalid window
	req, _ := http.NewRequest("GET", "/metrics/aggregated?window=invalid", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

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

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

	handler := NewAggregatedMetricsHandlerWithInterface(nil)
	router.GET("/metrics/aggregated", handler.GetAggregated)

	// Execute
	req, _ := http.NewRequest("GET", "/metrics/aggregated", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

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

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

	// Create a mock that returns nil aggregated metrics
	mockMetrics := &MockErrorMetrics{
		aggregatedMetrics: nil,
	}
	handler := NewAggregatedMetricsHandlerWithInterface(mockMetrics)
	router.GET("/metrics/aggregated", handler.GetAggregated)

	// Execute
	req, _ := http.NewRequest("GET", "/metrics/aggregated", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Assert - Should return 500 because aggregatedMetrics is nil
	assert.Equal(t, http.StatusInternalServerError, w.Code)

	var response map[string]interface{}
	err := json.Unmarshal(w.Body.Bytes(), &response)
	assert.NoError(t, err)
	assert.Contains(t, response["error"].(string), "Aggregated metrics not available")
}

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

	mockMetrics := &MockErrorMetrics{
		aggregatedMetrics: &metrics.AggregatedMetrics{},
	}
	router.GET("/metrics/aggregated", AggregatedMetricsWithInterface(mockMetrics))

	// Execute
	req, _ := http.NewRequest("GET", "/metrics/aggregated", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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