package utils

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

	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/stretchr/testify/assert"
)

func TestInitLogger_Debug(t *testing.T) {
	InitLogger(true)
	assert.Equal(t, zerolog.DebugLevel, zerolog.GlobalLevel())
}

func TestInitLogger_Production(t *testing.T) {
	InitLogger(false)
	assert.Equal(t, zerolog.InfoLevel, zerolog.GlobalLevel())
}

func TestInitLoggerWithWriter_AdditionalWriter(t *testing.T) {
	var buf bytes.Buffer
	InitLoggerWithWriter(false, &buf)

	log.Info().Msg("test message")

	// The additional writer should have received JSON output
	assert.Contains(t, buf.String(), "test message")
}

func TestInitLoggerWithWriter_Debug_AdditionalWriter(t *testing.T) {
	var buf bytes.Buffer
	InitLoggerWithWriter(true, &buf)

	log.Info().Msg("debug test")

	// Additional writer receives JSON even in debug mode
	assert.Contains(t, buf.String(), "debug test")
}

func TestInitLoggerWithWriter_NilWriter(t *testing.T) {
	// Should not panic with nil additional writer
	InitLoggerWithWriter(false, nil)
	assert.Equal(t, zerolog.InfoLevel, zerolog.GlobalLevel())
}

func TestEchoLogger_ReturnsMiddleware(t *testing.T) {
	mw := EchoLogger()
	assert.NotNil(t, mw)

	// Test that it processes requests without error
	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/api/health/", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	err := handler(c)
	assert.NoError(t, err)
	assert.Equal(t, http.StatusOK, rec.Code)
}

func TestEchoRecovery_ReturnsMiddleware(t *testing.T) {
	mw := EchoRecovery()
	assert.NotNil(t, mw)

	// Test panic recovery
	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/api/panic/", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	handler := mw(func(c echo.Context) error {
		panic("test panic")
	})

	// Should not panic — the middleware recovers
	assert.NotPanics(t, func() {
		_ = handler(c)
	})
	assert.Equal(t, http.StatusInternalServerError, rec.Code)
	assert.Contains(t, rec.Body.String(), "Internal server error")
}

func TestEchoLogger_WithQueryParams(t *testing.T) {
	mw := EchoLogger()

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/api/tasks/?limit=10&offset=0", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	err := handler(c)
	assert.NoError(t, err)
}

func TestEchoLogger_ErrorStatus(t *testing.T) {
	mw := EchoLogger()

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/api/notfound/", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusNotFound, "not found")
	})

	err := handler(c)
	assert.NoError(t, err)
	assert.Equal(t, http.StatusNotFound, rec.Code)
}
