package config_test

import (
	"os"
	"testing"
	"time"

	"github.com/libnovel/backend/internal/config"
)

func TestLoad_Defaults(t *testing.T) {
	// Unset all relevant vars so we test pure defaults.
	unset := []string{
		"LOG_LEVEL",
		"POCKETBASE_URL", "POCKETBASE_ADMIN_EMAIL", "POCKETBASE_ADMIN_PASSWORD",
		"MINIO_ENDPOINT", "MINIO_PUBLIC_ENDPOINT", "MINIO_ACCESS_KEY", "MINIO_SECRET_KEY",
		"MINIO_USE_SSL", "MINIO_PUBLIC_USE_SSL",
		"MINIO_BUCKET_CHAPTERS", "MINIO_BUCKET_AUDIO", "MINIO_BUCKET_AVATARS",
		"KOKORO_URL", "KOKORO_VOICE",
		"BACKEND_HTTP_ADDR",
		"RUNNER_POLL_INTERVAL", "RUNNER_MAX_CONCURRENT_SCRAPE", "RUNNER_MAX_CONCURRENT_AUDIO",
		"RUNNER_WORKER_ID", "RUNNER_WORKERS", "RUNNER_TIMEOUT",
	}
	for _, k := range unset {
		t.Setenv(k, "")
	}

	cfg := config.Load()

	if cfg.LogLevel != "info" {
		t.Errorf("LogLevel: want info, got %q", cfg.LogLevel)
	}
	if cfg.PocketBase.URL != "http://localhost:8090" {
		t.Errorf("PocketBase.URL: want http://localhost:8090, got %q", cfg.PocketBase.URL)
	}
	if cfg.MinIO.BucketChapters != "chapters" {
		t.Errorf("MinIO.BucketChapters: want chapters, got %q", cfg.MinIO.BucketChapters)
	}
	if cfg.MinIO.UseSSL != false {
		t.Errorf("MinIO.UseSSL: want false, got %v", cfg.MinIO.UseSSL)
	}
	if cfg.MinIO.PublicUseSSL != true {
		t.Errorf("MinIO.PublicUseSSL: want true, got %v", cfg.MinIO.PublicUseSSL)
	}
	if cfg.Kokoro.DefaultVoice != "af_bella" {
		t.Errorf("Kokoro.DefaultVoice: want af_bella, got %q", cfg.Kokoro.DefaultVoice)
	}
	if cfg.HTTP.Addr != ":8080" {
		t.Errorf("HTTP.Addr: want :8080, got %q", cfg.HTTP.Addr)
	}
	if cfg.Runner.PollInterval != 30*time.Second {
		t.Errorf("Runner.PollInterval: want 30s, got %v", cfg.Runner.PollInterval)
	}
	if cfg.Runner.MaxConcurrentScrape != 1 {
		t.Errorf("Runner.MaxConcurrentScrape: want 1, got %d", cfg.Runner.MaxConcurrentScrape)
	}
	if cfg.Runner.MaxConcurrentAudio != 1 {
		t.Errorf("Runner.MaxConcurrentAudio: want 1, got %d", cfg.Runner.MaxConcurrentAudio)
	}
}

func TestLoad_EnvOverride(t *testing.T) {
	t.Setenv("LOG_LEVEL", "debug")
	t.Setenv("POCKETBASE_URL", "https://pb.libnovel.cc")
	t.Setenv("MINIO_USE_SSL", "true")
	t.Setenv("MINIO_PUBLIC_USE_SSL", "false")
	t.Setenv("RUNNER_POLL_INTERVAL", "1m")
	t.Setenv("RUNNER_MAX_CONCURRENT_SCRAPE", "5")
	t.Setenv("RUNNER_WORKER_ID", "homelab-01")
	t.Setenv("BACKEND_HTTP_ADDR", ":9090")
	t.Setenv("KOKORO_URL", "https://kokoro.libnovel.cc")

	cfg := config.Load()

	if cfg.LogLevel != "debug" {
		t.Errorf("LogLevel: want debug, got %q", cfg.LogLevel)
	}
	if cfg.PocketBase.URL != "https://pb.libnovel.cc" {
		t.Errorf("PocketBase.URL: want https://pb.libnovel.cc, got %q", cfg.PocketBase.URL)
	}
	if !cfg.MinIO.UseSSL {
		t.Error("MinIO.UseSSL: want true")
	}
	if cfg.MinIO.PublicUseSSL {
		t.Error("MinIO.PublicUseSSL: want false")
	}
	if cfg.Runner.PollInterval != time.Minute {
		t.Errorf("Runner.PollInterval: want 1m, got %v", cfg.Runner.PollInterval)
	}
	if cfg.Runner.MaxConcurrentScrape != 5 {
		t.Errorf("Runner.MaxConcurrentScrape: want 5, got %d", cfg.Runner.MaxConcurrentScrape)
	}
	if cfg.Runner.WorkerID != "homelab-01" {
		t.Errorf("Runner.WorkerID: want homelab-01, got %q", cfg.Runner.WorkerID)
	}
	if cfg.HTTP.Addr != ":9090" {
		t.Errorf("HTTP.Addr: want :9090, got %q", cfg.HTTP.Addr)
	}
	if cfg.Kokoro.URL != "https://kokoro.libnovel.cc" {
		t.Errorf("Kokoro.URL: want https://kokoro.libnovel.cc, got %q", cfg.Kokoro.URL)
	}
}

func TestLoad_InvalidInt_FallsToDefault(t *testing.T) {
	t.Setenv("RUNNER_MAX_CONCURRENT_SCRAPE", "notanumber")
	cfg := config.Load()
	if cfg.Runner.MaxConcurrentScrape != 1 {
		t.Errorf("want default 1, got %d", cfg.Runner.MaxConcurrentScrape)
	}
}

func TestLoad_InvalidDuration_FallsToDefault(t *testing.T) {
	t.Setenv("RUNNER_POLL_INTERVAL", "notaduration")
	cfg := config.Load()
	if cfg.Runner.PollInterval != 30*time.Second {
		t.Errorf("want default 30s, got %v", cfg.Runner.PollInterval)
	}
}

func TestLoad_WorkerID_FallsToHostname(t *testing.T) {
	t.Setenv("RUNNER_WORKER_ID", "")
	cfg := config.Load()
	host, _ := os.Hostname()
	if host != "" && cfg.Runner.WorkerID != host {
		t.Errorf("want hostname %q, got %q", host, cfg.Runner.WorkerID)
	}
}
