package logger

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gorm.io/gorm"
	gormlogger "gorm.io/gorm/logger"
)

func TestNewGormLogger(t *testing.T) {
	logger := zap.NewNop()
	gormLogger := NewGormLogger(logger)

	assert.NotNil(t, gormLogger)
	assert.NotNil(t, gormLogger.logger)
	assert.Equal(t, zap.DebugLevel, gormLogger.level)
}

func TestGormLogger_LogMode(t *testing.T) {
	logger := zap.NewNop()
	gormLogger := NewGormLogger(logger)

	tests := []struct {
		name          string
		level         gormlogger.LogLevel
		expectedLevel zapcore.Level
	}{
		{"Silent", gormlogger.Silent, zapcore.PanicLevel},
		{"Error", gormlogger.Error, zapcore.ErrorLevel},
		{"Warn", gormlogger.Warn, zapcore.WarnLevel},
		{"Info", gormlogger.Info, zapcore.DebugLevel},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			newLogger := gormLogger.LogMode(tt.level)
			assert.NotNil(t, newLogger)
		})
	}
}

func TestGormLogger_Trace(t *testing.T) {
	logger := zap.NewNop()
	gormLogger := NewGormLogger(logger)

	ctx := context.Background()
	begin := time.Now()

	fc := func() (string, int64) {
		return "SELECT * FROM users", 10
	}

	gormLogger.Trace(ctx, begin, fc, nil)
}

func TestGormLogger_TraceWithError(t *testing.T) {
	logger := zap.NewNop()
	gormLogger := NewGormLogger(logger)

	ctx := context.Background()
	begin := time.Now()

	fc := func() (string, int64) {
		return "SELECT * FROM users", 0
	}

	gormLogger.Trace(ctx, begin, fc, gorm.ErrRecordNotFound)
}

func TestGormLogger_Info(t *testing.T) {
	logger := zap.NewNop()
	gormLogger := NewGormLogger(logger)

	ctx := context.Background()
	gormLogger.Info(ctx, "test info message")
}

func TestGormLogger_Warn(t *testing.T) {
	logger := zap.NewNop()
	gormLogger := NewGormLogger(logger)

	ctx := context.Background()
	gormLogger.Warn(ctx, "test warn message")
}

func TestGormLogger_Error(t *testing.T) {
	logger := zap.NewNop()
	gormLogger := NewGormLogger(logger)

	ctx := context.Background()
	gormLogger.Error(ctx, "test error message")
}

func TestGormLogger_FormatSQL(t *testing.T) {
	logger := zap.NewNop()
	gormLogger := NewGormLogger(logger)

	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "simple query",
			input:    "SELECT * FROM users",
			expected: "SELECT * FROM users",
		},
		{
			name:     "query with extra spaces",
			input:    "SELECT  *   FROM    users",
			expected: "SELECT * FROM users",
		},
		{
			name:     "query with newlines",
			input:    "SELECT\n*\nFROM\nusers",
			expected: "SELECT * FROM users",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := gormLogger.formatSQL(tt.input)
			assert.Equal(t, tt.expected, result)
		})
	}
}
