package config

import (
	"testing"
	"time"
)

// env builds a getenv func over a map, defaulting the two required vars so
// each test only states what it cares about.
func env(overrides map[string]string) func(string) string {
	base := map[string]string{
		"THERMOGRAPH_INTERNAL_TOKEN":    "sekrit",
		"THERMOGRAPH_API_BASE_INTERNAL": "http://web:8137",
	}
	for k, v := range overrides {
		base[k] = v
	}
	return func(k string) string { return base[k] }
}

func TestRequiredVarsRefuseToStart(t *testing.T) {
	for _, missing := range []string{"THERMOGRAPH_INTERNAL_TOKEN", "THERMOGRAPH_API_BASE_INTERNAL"} {
		if _, err := load(env(map[string]string{missing: ""})); err == nil {
			t.Errorf("expected error when %s is unset, got nil", missing)
		}
	}
	if cfg, err := load(env(nil)); err != nil || cfg == nil {
		t.Fatalf("both required vars set: unexpected error %v", err)
	}
}

func TestTruthyParsing(t *testing.T) {
	cases := []struct {
		flag, token string
		want        bool
	}{
		// Must match the Python _TRUTHY set exactly.
		{"1", "tok", true},
		{"true", "tok", true},
		{"TRUE", "tok", true},
		{"yes", "tok", true},
		{"on", "tok", true},
		{" on ", "tok", true}, // whitespace tolerated, like .strip() in Python
		{"0", "tok", false},
		{"false", "tok", false},
		{"", "tok", false},
		{"enabled", "tok", false}, // not in the truthy set
		// Flag alone is not enough: no token means no gateway.
		{"1", "", false},
	}
	for _, c := range cases {
		cfg, err := load(env(map[string]string{
			"THERMOGRAPH_DISCORD_BOT":       c.flag,
			"THERMOGRAPH_DISCORD_BOT_TOKEN": c.token,
		}))
		if err != nil {
			t.Fatalf("flag=%q token=%q: unexpected error %v", c.flag, c.token, err)
		}
		if cfg.DiscordEnabled != c.want {
			t.Errorf("flag=%q token=%q: DiscordEnabled=%v, want %v", c.flag, c.token, cfg.DiscordEnabled, c.want)
		}
	}
}

func TestIntervalDefaultsAndFallbacks(t *testing.T) {
	cases := []struct {
		name           string
		warm, indexnow string
		wantWarm       time.Duration
		wantIndexNow   time.Duration
	}{
		{"unset uses defaults", "", "", 24 * time.Hour, 6 * time.Hour},
		{"explicit values win", "12", "3", 12 * time.Hour, 3 * time.Hour},
		// Malformed values degrade to the default instead of erroring, like
		// the Python int(... or 24) they replace.
		{"garbage falls back", "soon", "1.5", 24 * time.Hour, 6 * time.Hour},
		{"non-positive falls back", "0", "-2", 24 * time.Hour, 6 * time.Hour},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			cfg, err := load(env(map[string]string{
				"THERMOGRAPH_WARM_CITIES_INTERVAL_HOURS": c.warm,
				"THERMOGRAPH_INDEXNOW_INTERVAL_HOURS":    c.indexnow,
			}))
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if cfg.WarmCitiesInterval != c.wantWarm {
				t.Errorf("WarmCitiesInterval=%v, want %v", cfg.WarmCitiesInterval, c.wantWarm)
			}
			if cfg.IndexNowInterval != c.wantIndexNow {
				t.Errorf("IndexNowInterval=%v, want %v", cfg.IndexNowInterval, c.wantIndexNow)
			}
		})
	}
}
