package middleware

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

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

func TestErrorHandler_StackTrace(t *testing.T) {
	// Setup Logger Observer
	core, logs := observer.New(zapcore.ErrorLevel)
	logger := zap.New(core)

	tests := []struct {
		name              string
		includeStackTrace bool
		expectStack       bool
	}{
		{
			name:              "IncludeStackTrace_True",
			includeStackTrace: true,
			expectStack:       true,
		},
		{
			name:              "IncludeStackTrace_False",
			includeStackTrace: false,
			expectStack:       false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			logs.TakeAll() // Clear logs

			gin.SetMode(gin.TestMode)
			r := gin.New()
			r.Use(ErrorHandler(logger, nil, tt.includeStackTrace))
			r.GET("/error", func(c *gin.Context) {
				c.Error(errors.New("generic error"))
			})

			req, _ := http.NewRequest("GET", "/error", nil)
			w := httptest.NewRecorder()
			r.ServeHTTP(w, req)

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

			// Check logs
			entries := logs.All()
			assert.NotEmpty(t, entries, "Should have logged an error")
			entry := entries[0]

			fields := entry.ContextMap()
			_, hasStack := fields["stack_trace"]

			if tt.expectStack {
				assert.True(t, hasStack, "Log should contain stack_trace")
			} else {
				assert.False(t, hasStack, "Log should NOT contain stack_trace")
			}
		})
	}
}
