package config

import (
	"path/filepath"
	"testing"
)

func TestDefaults(t *testing.T) {
	clearConfigEnv(t)

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Load returned error: %v", err)
	}

	if cfg.UploadsDir != filepath.Join("data", "uploads") {
		t.Fatalf("unexpected uploads dir: %s", cfg.UploadsDir)
	}
	if cfg.DBDir != filepath.Join("data", "db") {
		t.Fatalf("unexpected db dir: %s", cfg.DBDir)
	}
	if !cfg.GuestUploadsEnabled || !cfg.APIEnabled || !cfg.ZipDownloadsEnabled || !cfg.OneTimeDownloadsEnabled {
		t.Fatal("expected default guest/API/download toggles to be enabled")
	}
	if cfg.AdminUsername != "admin" {
		t.Fatalf("unexpected admin username: %s", cfg.AdminUsername)
	}
	if cfg.AdminPassword != "" {
		t.Fatal("expected default admin password to be empty")
	}
}

func TestEnvironmentOverrides(t *testing.T) {
	clearConfigEnv(t)
	t.Setenv("WARPBOX_DATA_DIR", "/tmp/warpbox-test")
	t.Setenv("WARPBOX_GUEST_UPLOADS_ENABLED", "false")
	t.Setenv("WARPBOX_API_ENABLED", "false")
	t.Setenv("WARPBOX_GLOBAL_MAX_FILE_SIZE_BYTES", "100")
	t.Setenv("WARPBOX_BOX_POLL_INTERVAL_MS", "2000")
	t.Setenv("WARPBOX_ADMIN_USERNAME", "root")
	t.Setenv("WARPBOX_ONE_TIME_DOWNLOAD_RETRY_ON_FAILURE", "true")

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Load returned error: %v", err)
	}

	if cfg.UploadsDir != filepath.Join("/tmp/warpbox-test", "uploads") {
		t.Fatalf("unexpected uploads dir: %s", cfg.UploadsDir)
	}
	if cfg.GuestUploadsEnabled || cfg.APIEnabled {
		t.Fatal("expected boolean environment overrides to be applied")
	}
	if cfg.GlobalMaxFileSizeBytes != 100 {
		t.Fatalf("unexpected global max file size: %d", cfg.GlobalMaxFileSizeBytes)
	}
	if cfg.BoxPollIntervalMS != 2000 {
		t.Fatalf("unexpected poll interval: %d", cfg.BoxPollIntervalMS)
	}
	if cfg.AdminUsername != "root" {
		t.Fatalf("unexpected admin username: %s", cfg.AdminUsername)
	}
	if !cfg.OneTimeDownloadRetryOnFailure {
		t.Fatal("expected one-time retry-on-failure env override to be applied")
	}
	if cfg.Source(SettingAPIEnabled) != SourceEnv {
		t.Fatalf("expected API setting source to be env, got %s", cfg.Source(SettingAPIEnabled))
	}
}

func TestMegabyteSizeEnvironmentOverrides(t *testing.T) {
	clearConfigEnv(t)
	t.Setenv("WARPBOX_GLOBAL_MAX_FILE_SIZE_MB", "2048")
	t.Setenv("WARPBOX_GLOBAL_MAX_BOX_SIZE_MB", "4096")

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Load returned error: %v", err)
	}

	if cfg.GlobalMaxFileSizeBytes != 2048*1024*1024 {
		t.Fatalf("unexpected global max file size: %d", cfg.GlobalMaxFileSizeBytes)
	}
	if cfg.GlobalMaxBoxSizeBytes != 4096*1024*1024 {
		t.Fatalf("unexpected global max box size: %d", cfg.GlobalMaxBoxSizeBytes)
	}
}

func TestByteSizeEnvironmentOverridesTakePrecedence(t *testing.T) {
	clearConfigEnv(t)
	t.Setenv("WARPBOX_GLOBAL_MAX_FILE_SIZE_MB", "2048")
	t.Setenv("WARPBOX_GLOBAL_MAX_FILE_SIZE_BYTES", "100")

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Load returned error: %v", err)
	}

	if cfg.GlobalMaxFileSizeBytes != 100 {
		t.Fatalf("unexpected global max file size: %d", cfg.GlobalMaxFileSizeBytes)
	}
}

func TestInvalidEnvironmentValues(t *testing.T) {
	clearConfigEnv(t)
	t.Setenv("WARPBOX_SESSION_TTL_SECONDS", "1")
	if _, err := Load(); err == nil {
		t.Fatal("expected invalid session ttl to fail")
	}

	clearConfigEnv(t)
	t.Setenv("WARPBOX_GUEST_UPLOADS_ENABLED", "maybe")
	if _, err := Load(); err == nil {
		t.Fatal("expected invalid boolean to fail")
	}
}

func TestSettingsOverridePrecedence(t *testing.T) {
	clearConfigEnv(t)
	t.Setenv("WARPBOX_API_ENABLED", "true")

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Load returned error: %v", err)
	}
	if err := cfg.ApplyOverrides(map[string]string{SettingAPIEnabled: "false"}); err != nil {
		t.Fatalf("ApplyOverrides returned error: %v", err)
	}

	if cfg.APIEnabled {
		t.Fatal("expected DB override to beat environment value")
	}
	if cfg.Source(SettingAPIEnabled) != SourceDB {
		t.Fatalf("expected DB source, got %s", cfg.Source(SettingAPIEnabled))
	}
}

func TestSettingsOverrideValidation(t *testing.T) {
	clearConfigEnv(t)

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Load returned error: %v", err)
	}
	if err := cfg.ApplyOverride(SettingDefaultGuestExpirySecs, "-1"); err == nil {
		t.Fatal("expected negative expiry override to fail")
	}
	if err := cfg.ApplyOverride(SettingGlobalMaxFileSizeBytes, "1"); err == nil {
		t.Fatal("expected hard limit override to fail")
	}
}

func clearConfigEnv(t *testing.T) {
	t.Helper()
	for _, name := range []string{
		"WARPBOX_DATA_DIR",
		"WARPBOX_ADMIN_PASSWORD",
		"WARPBOX_ADMIN_USERNAME",
		"WARPBOX_ADMIN_EMAIL",
		"WARPBOX_ADMIN_ENABLED",
		"WARPBOX_ALLOW_ADMIN_SETTINGS_OVERRIDE",
		"WARPBOX_ADMIN_COOKIE_SECURE",
		"WARPBOX_GUEST_UPLOADS_ENABLED",
		"WARPBOX_API_ENABLED",
		"WARPBOX_ZIP_DOWNLOADS_ENABLED",
		"WARPBOX_ONE_TIME_DOWNLOADS_ENABLED",
		"WARPBOX_ONE_TIME_DOWNLOAD_RETRY_ON_FAILURE",
		"WARPBOX_RENEW_ON_ACCESS_ENABLED",
		"WARPBOX_RENEW_ON_DOWNLOAD_ENABLED",
		"WARPBOX_DEFAULT_GUEST_EXPIRY_SECONDS",
		"WARPBOX_MAX_GUEST_EXPIRY_SECONDS",
		"WARPBOX_GLOBAL_MAX_FILE_SIZE_MB",
		"WARPBOX_GLOBAL_MAX_FILE_SIZE_BYTES",
		"WARPBOX_GLOBAL_MAX_BOX_SIZE_MB",
		"WARPBOX_GLOBAL_MAX_BOX_SIZE_BYTES",
		"WARPBOX_DEFAULT_USER_MAX_FILE_SIZE_MB",
		"WARPBOX_DEFAULT_USER_MAX_FILE_SIZE_BYTES",
		"WARPBOX_DEFAULT_USER_MAX_BOX_SIZE_MB",
		"WARPBOX_DEFAULT_USER_MAX_BOX_SIZE_BYTES",
		"WARPBOX_SESSION_TTL_SECONDS",
		"WARPBOX_BOX_POLL_INTERVAL_MS",
		"WARPBOX_THUMBNAIL_BATCH_SIZE",
		"WARPBOX_THUMBNAIL_INTERVAL_SECONDS",
	} {
		t.Setenv(name, "")
	}
}
