package config

import (
	"log/slog"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

func TestLoadFromEnvDefaultsLogConfig(t *testing.T) {
	t.Setenv("AGENTTEAM_DATABASE_DSN", "root:@tcp(127.0.0.1:4000)/agentteam?tls=false")
	t.Setenv("AGENTTEAM_LOG_LEVEL", "info")

	cfg, err := LoadFromEnv()
	require.NoError(t, err)
	require.Equal(t, DefaultLogConfig(), cfg.Log)
}

func TestLoadFromEnvReadsFileLogConfig(t *testing.T) {
	t.Setenv("AGENTTEAM_DATABASE_DSN", "root:@tcp(127.0.0.1:4000)/agentteam?tls=false")
	t.Setenv("AGENTTEAM_LOG_LEVEL", "warn")
	t.Setenv("AGENTTEAM_LOG_FORMAT", "text")
	t.Setenv("AGENTTEAM_LOG_OUTPUT", "both")
	t.Setenv("AGENTTEAM_LOG_FILE", filepath.Join(t.TempDir(), "agentteam.log"))
	t.Setenv("AGENTTEAM_LOG_FILE_MAX_SIZE_MB", "64")
	t.Setenv("AGENTTEAM_LOG_FILE_MAX_DAYS", "0")
	t.Setenv("AGENTTEAM_LOG_FILE_MAX_BACKUPS", "3")
	t.Setenv("AGENTTEAM_LOG_FILE_COMPRESSION", "none")
	t.Setenv("AGENTTEAM_LOG_FILE_BUFFER_SIZE_KB", "0")
	t.Setenv("AGENTTEAM_LOG_FILE_FLUSH_INTERVAL", "250ms")

	cfg, err := LoadFromEnv()
	require.NoError(t, err)
	require.Equal(t, slog.LevelWarn, cfg.Log.Level)
	require.Equal(t, LogFormatText, cfg.Log.Format)
	require.Equal(t, LogOutputBoth, cfg.Log.Output)
	require.Equal(t, 64, cfg.Log.MaxSizeMB)
	require.Zero(t, cfg.Log.MaxDays)
	require.Equal(t, 3, cfg.Log.MaxBackups)
	require.Equal(t, LogCompressionNone, cfg.Log.Compression)
	require.Zero(t, cfg.Log.BufferSizeKB)
	require.Equal(t, 250*time.Millisecond, cfg.Log.FlushInterval)
}

func TestLoadFromEnvRejectsInvalidLogConfig(t *testing.T) {
	filePath := filepath.Join(t.TempDir(), "agentteam.log")
	tests := []struct {
		name  string
		env   map[string]string
		error string
	}{
		{name: "level", env: map[string]string{"AGENTTEAM_LOG_LEVEL": "verbose"}, error: "AGENTTEAM_LOG_LEVEL must be one of debug, info, warn, or error"},
		{name: "format", env: map[string]string{"AGENTTEAM_LOG_FORMAT": "console"}, error: "AGENTTEAM_LOG_FORMAT must be one of json or text"},
		{name: "output", env: map[string]string{"AGENTTEAM_LOG_OUTPUT": "stderr"}, error: "AGENTTEAM_LOG_OUTPUT must be one of stdout, file, or both"},
		{name: "stdout file", env: map[string]string{"AGENTTEAM_LOG_FILE": filePath}, error: "AGENTTEAM_LOG_FILE must be empty when AGENTTEAM_LOG_OUTPUT=stdout"},
		{name: "missing file", env: map[string]string{"AGENTTEAM_LOG_OUTPUT": "file"}, error: "AGENTTEAM_LOG_FILE is required when AGENTTEAM_LOG_OUTPUT=file"},
		{name: "relative file", env: map[string]string{"AGENTTEAM_LOG_OUTPUT": "file", "AGENTTEAM_LOG_FILE": "agentteam.log"}, error: "AGENTTEAM_LOG_FILE must be an absolute path"},
		{name: "unbounded", env: map[string]string{"AGENTTEAM_LOG_OUTPUT": "file", "AGENTTEAM_LOG_FILE": filePath, "AGENTTEAM_LOG_FILE_MAX_DAYS": "0", "AGENTTEAM_LOG_FILE_MAX_BACKUPS": "0"}, error: "AGENTTEAM_LOG_FILE_MAX_DAYS or AGENTTEAM_LOG_FILE_MAX_BACKUPS must be positive when file logging is enabled"},
		{name: "size", env: map[string]string{"AGENTTEAM_LOG_FILE_MAX_SIZE_MB": "0"}, error: "AGENTTEAM_LOG_FILE_MAX_SIZE_MB must be between 1 and 4096"},
		{name: "days", env: map[string]string{"AGENTTEAM_LOG_FILE_MAX_DAYS": "-1"}, error: "AGENTTEAM_LOG_FILE_MAX_DAYS must be non-negative"},
		{name: "backups", env: map[string]string{"AGENTTEAM_LOG_FILE_MAX_BACKUPS": "-1"}, error: "AGENTTEAM_LOG_FILE_MAX_BACKUPS must be non-negative"},
		{name: "compression", env: map[string]string{"AGENTTEAM_LOG_FILE_COMPRESSION": "zip"}, error: "AGENTTEAM_LOG_FILE_COMPRESSION must be one of gzip or none"},
		{name: "buffer", env: map[string]string{"AGENTTEAM_LOG_FILE_BUFFER_SIZE_KB": "-1"}, error: "AGENTTEAM_LOG_FILE_BUFFER_SIZE_KB must be non-negative"},
		{name: "flush", env: map[string]string{"AGENTTEAM_LOG_FILE_FLUSH_INTERVAL": "0s"}, error: "AGENTTEAM_LOG_FILE_FLUSH_INTERVAL must be positive"},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			t.Setenv("AGENTTEAM_DATABASE_DSN", "root:@tcp(127.0.0.1:4000)/agentteam?tls=false")
			for key, value := range test.env {
				t.Setenv(key, value)
			}
			_, err := LoadFromEnv()
			require.EqualError(t, err, test.error)
		})
	}
}
