package logger

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
)

func TestNew_StdoutOnly(t *testing.T) {
	logger, err := New(Config{Level: "info"})
	require.NoError(t, err)
	require.NotNil(t, logger)
	assert.NoError(t, logger.Sync())
}

func TestNew_WithFileOutput(t *testing.T) {
	dir := filepath.Join(os.TempDir(), "nex-logger-test")
	require.NoError(t, os.MkdirAll(dir, 0o755))
	defer os.RemoveAll(dir)

	logger, err := New(Config{
		Level:      "debug",
		Path:       dir,
		MaxSize:    10,
		MaxBackups: 3,
		MaxAge:     7,
		Compress:   false,
	})
	require.NoError(t, err)
	require.NotNil(t, logger)

	logger.Info("test log message")
	_ = logger.Sync()

	// 验证日志文件已创建
	files, err := os.ReadDir(dir)
	require.NoError(t, err)
	assert.NotEmpty(t, files, "日志目录应包含文件")
}

func TestNew_AllLevels(t *testing.T) {
	levels := []string{"debug", "info", "warn", "error"}
	for _, level := range levels {
		logger, err := New(Config{Level: level})
		assert.NoError(t, err, "级别 %s 应有效", level)
		assert.NotNil(t, logger)
		assert.NoError(t, logger.Sync())
	}
}

func TestNew_EmptyLevel(t *testing.T) {
	// 空级别应默认为 info
	logger, err := New(Config{Level: ""})
	require.NoError(t, err)
	require.NotNil(t, logger)
	assert.NoError(t, logger.Sync())
}

func TestNew_InvalidPath(t *testing.T) {
	// 不可写的路径
	logger, err := New(Config{
		Level: "info",
		Path:  "/nonexistent/deeply/nested/path/logs",
	})
	// 应能创建 logger（错误在写入时发生）
	// 实际上 lumberjack 会尝试创建目录
	_ = logger
	_ = err
}

func TestParseLevel(t *testing.T) {
	tests := []struct {
		input string
		valid bool
	}{
		{"debug", true},
		{"info", true},
		{"warn", true},
		{"error", true},
		{"", true},        // 默认为 info
		{"invalid", true}, // 默认为 info
	}
	for _, tt := range tests {
		_, err := parseLevel(tt.input)
		assert.NoError(t, err, "parseLevel(%q) 不应报错", tt.input)
	}
}

func TestLogFilePath(t *testing.T) {
	result := logFilePath(filepath.Join("var", "log"))
	assert.Contains(t, result, "nex-")
	assert.Contains(t, result, ".log")
}

func TestLogFileName(t *testing.T) {
	name := logFileName()
	assert.Contains(t, name, "nex-")
	assert.Contains(t, name, ".log")
	assert.Len(t, name, len("nex-2006-01-02.log"))
}

func TestNewRotateWriter_Defaults(t *testing.T) {
	cfg := Config{
		Path:     t.TempDir(),
		MaxSize:  0,
		MaxAge:   0,
		Compress: true,
	}
	writer := newRotateWriter(cfg)
	require.NotNil(t, writer)
	assert.Equal(t, 100, writer.MaxSize)
	assert.Equal(t, 10, writer.MaxBackups)
	assert.Equal(t, 30, writer.MaxAge)
}

func TestWithRequestID(t *testing.T) {
	logger, err := New(Config{Level: "info"})
	require.NoError(t, err)

	contextLogger := WithRequestID(logger, "test-request-123")
	assert.NotNil(t, contextLogger)
	assert.IsType(t, &zap.Logger{}, contextLogger)
}

func TestWithContext(t *testing.T) {
	logger, err := New(Config{Level: "info"})
	require.NoError(t, err)

	contextLogger := WithContext(logger, map[string]interface{}{
		"key1": "value1",
		"key2": 42,
	})
	assert.NotNil(t, contextLogger)
}
