package middleware

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

	"github.com/gin-gonic/gin"
)

func TestRequestID_GeneratesNewID(t *testing.T) {
	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.Use(RequestID())

	router.GET("/test", func(c *gin.Context) {
		requestID := GetRequestID(c)
		if requestID == "" {
			t.Error("Expected request ID to be set")
		}
		c.JSON(http.StatusOK, gin.H{"request_id": requestID})
	})

	req := httptest.NewRequest(http.MethodGet, "/test", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}

	// Check response header
	requestID := w.Header().Get(RequestIDHeader)
	if requestID == "" {
		t.Error("Expected X-Request-ID header in response")
	}

	// Check correlation ID header
	correlationID := w.Header().Get(CorrelationIDHeader)
	if correlationID == "" {
		t.Error("Expected X-Correlation-ID header in response")
	}

	if requestID != correlationID {
		t.Error("X-Request-ID and X-Correlation-ID should match")
	}
}

func TestRequestID_PropagatesExistingID(t *testing.T) {
	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.Use(RequestID())

	customID := "custom-request-id-12345"

	router.GET("/test", func(c *gin.Context) {
		requestID := GetRequestID(c)
		if requestID != customID {
			t.Errorf("Expected request ID %s, got %s", customID, requestID)
		}
		c.JSON(http.StatusOK, gin.H{"request_id": requestID})
	})

	req := httptest.NewRequest(http.MethodGet, "/test", nil)
	req.Header.Set(RequestIDHeader, customID)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}

	responseID := w.Header().Get(RequestIDHeader)
	if responseID != customID {
		t.Errorf("Expected response header %s, got %s", customID, responseID)
	}
}

func TestRequestID_PropagatesCorrelationID(t *testing.T) {
	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.Use(RequestID())

	correlationID := "correlation-id-67890"

	router.GET("/test", func(c *gin.Context) {
		requestID := GetRequestID(c)
		if requestID != correlationID {
			t.Errorf("Expected request ID %s, got %s", correlationID, requestID)
		}
		c.JSON(http.StatusOK, gin.H{})
	})

	req := httptest.NewRequest(http.MethodGet, "/test", nil)
	req.Header.Set(CorrelationIDHeader, correlationID)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}

	// Both headers should be set with the correlation ID
	if w.Header().Get(RequestIDHeader) != correlationID {
		t.Error("X-Request-ID should match X-Correlation-ID")
	}
}

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

	// No RequestID middleware
	router.GET("/test", func(c *gin.Context) {
		requestID := GetRequestID(c)
		if requestID != "" {
			t.Errorf("Expected empty request ID, got %s", requestID)
		}
		c.JSON(http.StatusOK, gin.H{})
	})

	req := httptest.NewRequest(http.MethodGet, "/test", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}
}

func TestRequestIDFromContext_IsAliasForGetRequestID(t *testing.T) {
	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.Use(RequestID())

	router.GET("/test", func(c *gin.Context) {
		id1 := GetRequestID(c)
		id2 := RequestIDFromContext(c)
		if id1 != id2 {
			t.Errorf("GetRequestID and RequestIDFromContext should return same value")
		}
		c.JSON(http.StatusOK, gin.H{})
	})

	req := httptest.NewRequest(http.MethodGet, "/test", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}
}
