package config

import (
	"testing"
	"time"

	pkgtel "scrabble/pkg/telemetry"
)

// TestLoadTelemetryDefaults verifies the gateway telemetry defaults: the
// "scrabble-gateway" service name and both exporters off.
func TestLoadTelemetryDefaults(t *testing.T) {
	c, err := Load()
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if c.Telemetry.ServiceName != defaultServiceName {
		t.Errorf("Telemetry.ServiceName = %q, want %q", c.Telemetry.ServiceName, defaultServiceName)
	}
	if c.Telemetry.TracesExporter != pkgtel.ExporterNone || c.Telemetry.MetricsExporter != pkgtel.ExporterNone {
		t.Errorf("exporters = %q/%q, want none/none", c.Telemetry.TracesExporter, c.Telemetry.MetricsExporter)
	}
}

// TestLoadRejectsUnsupportedExporter verifies an exporter outside the supported
// set fails validation.
func TestLoadRejectsUnsupportedExporter(t *testing.T) {
	t.Setenv("GATEWAY_OTEL_METRICS_EXPORTER", "prometheus")
	if _, err := Load(); err == nil {
		t.Fatal("Load: expected an error for an unsupported exporter, got nil")
	}
}

// TestLoadMaxBodyBytes verifies the body-cap default and that a non-positive
// override fails validation.
func TestLoadMaxBodyBytes(t *testing.T) {
	c, err := Load()
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if c.MaxBodyBytes != DefaultMaxBodyBytes {
		t.Errorf("MaxBodyBytes = %d, want %d", c.MaxBodyBytes, DefaultMaxBodyBytes)
	}
	t.Setenv("GATEWAY_MAX_BODY_BYTES", "0")
	if _, err := Load(); err == nil {
		t.Fatal("Load: expected an error for a non-positive body cap, got nil")
	}
}

// TestLoadMinClientVersion verifies the client-version gate config: dormant (empty) by
// default, a parseable version accepted, and an unparseable one rejected.
func TestLoadMinClientVersion(t *testing.T) {
	c, err := Load()
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if c.MinClientVersion != "" {
		t.Errorf("MinClientVersion = %q, want empty (gate dormant)", c.MinClientVersion)
	}
	t.Setenv("GATEWAY_MIN_CLIENT_VERSION", "v1.16.0")
	if c, err = Load(); err != nil {
		t.Fatalf("Load with a valid min version: %v", err)
	}
	if c.MinClientVersion != "v1.16.0" {
		t.Errorf("MinClientVersion = %q, want %q", c.MinClientVersion, "v1.16.0")
	}
	t.Setenv("GATEWAY_MIN_CLIENT_VERSION", "dev")
	if _, err := Load(); err == nil {
		t.Fatal("Load: expected an error for an unparseable GATEWAY_MIN_CLIENT_VERSION, got nil")
	}
}

// TestLoadRecommendedClientVersion verifies the soft-tier config: dormant (empty) by default, a
// parseable version accepted (standing alone with no minimum, or at/above one), an unparseable one
// rejected, and a recommended below the minimum rejected.
func TestLoadRecommendedClientVersion(t *testing.T) {
	c, err := Load()
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if c.RecommendedClientVersion != "" {
		t.Errorf("RecommendedClientVersion = %q, want empty (soft tier dormant)", c.RecommendedClientVersion)
	}
	// Stands alone with no minimum configured.
	t.Setenv("GATEWAY_RECOMMENDED_CLIENT_VERSION", "v1.20.0")
	if c, err = Load(); err != nil {
		t.Fatalf("Load with a valid recommended version (no min): %v", err)
	}
	if c.RecommendedClientVersion != "v1.20.0" {
		t.Errorf("RecommendedClientVersion = %q, want %q", c.RecommendedClientVersion, "v1.20.0")
	}
	// At or above the minimum is accepted.
	t.Setenv("GATEWAY_MIN_CLIENT_VERSION", "v1.16.0")
	if _, err = Load(); err != nil {
		t.Fatalf("Load with recommended >= min: %v", err)
	}
	// Below the minimum is rejected.
	t.Setenv("GATEWAY_RECOMMENDED_CLIENT_VERSION", "v1.10.0")
	if _, err := Load(); err == nil {
		t.Fatal("Load: expected an error for a recommended version below the minimum, got nil")
	}
	// Unparseable is rejected.
	t.Setenv("GATEWAY_RECOMMENDED_CLIENT_VERSION", "dev")
	if _, err := Load(); err == nil {
		t.Fatal("Load: expected an error for an unparseable GATEWAY_RECOMMENDED_CLIENT_VERSION, got nil")
	}
}

// TestLoadAbuseDefaults verifies the anti-abuse ban defaults: disabled (prod-only),
// the agreed thresholds, and no honeytoken.
func TestLoadAbuseDefaults(t *testing.T) {
	c, err := Load()
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	want := DefaultAbuse()
	if c.Abuse != want {
		t.Errorf("Abuse = %+v, want %+v", c.Abuse, want)
	}
	if c.Abuse.BanEnabled {
		t.Error("ban must default to disabled (enabled only in prod)")
	}
}

// TestLoadAbuseOverrides verifies the anti-abuse environment variables are parsed.
func TestLoadAbuseOverrides(t *testing.T) {
	t.Setenv("GATEWAY_ABUSE_BAN_ENABLED", "true")
	t.Setenv("GATEWAY_ABUSE_BAN_THRESHOLD", "50")
	t.Setenv("GATEWAY_ABUSE_BAN_WINDOW", "90s")
	t.Setenv("GATEWAY_ABUSE_BAN_DURATION", "30m")
	t.Setenv("GATEWAY_HONEYTOKEN", "deadbeef")
	c, err := Load()
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	want := AbuseConfig{
		BanEnabled:   true,
		BanThreshold: 50,
		BanWindow:    90 * time.Second,
		BanDuration:  30 * time.Minute,
		Honeytoken:   "deadbeef",
	}
	if c.Abuse != want {
		t.Errorf("Abuse = %+v, want %+v", c.Abuse, want)
	}
}

// TestLoadAbuseRejectsBadThreshold verifies an enabled ban with a non-positive
// threshold fails validation.
func TestLoadAbuseRejectsBadThreshold(t *testing.T) {
	t.Setenv("GATEWAY_ABUSE_BAN_ENABLED", "true")
	t.Setenv("GATEWAY_ABUSE_BAN_THRESHOLD", "0")
	if _, err := Load(); err == nil {
		t.Fatal("Load: expected an error for an enabled ban with a zero threshold, got nil")
	}
}
