package serverruntime

import (
	"testing"
	"time"
)

func TestRuntimeDBPoolRoleConfigFromEnv(t *testing.T) {
	tests := []struct {
		name                string
		role                namedDBPoolRole
		overrideMaxOpen     string
		overridePingTimeout string
		wantDefaultMaxOpen  int
		wantOverrideMaxOpen int
		wantOverrideTimeout time.Duration
	}{
		{
			name:                "connector ingress",
			role:                runtimeDBPoolRoles[0],
			overrideMaxOpen:     "8",
			overridePingTimeout: "750ms",
			wantDefaultMaxOpen:  defaultConnectorIngressDBMaxOpen,
			wantOverrideMaxOpen: 8,
			wantOverrideTimeout: 750 * time.Millisecond,
		},
		{
			name:                "connector push",
			role:                runtimeDBPoolRoles[1],
			overrideMaxOpen:     "64",
			overridePingTimeout: "750ms",
			wantDefaultMaxOpen:  defaultConnectorPushDBMaxOpen,
			wantOverrideMaxOpen: 64,
			wantOverrideTimeout: 750 * time.Millisecond,
		},
		{
			name:                "outbox worker",
			role:                runtimeDBPoolRoles[2],
			overrideMaxOpen:     "48",
			overridePingTimeout: "1250ms",
			wantDefaultMaxOpen:  defaultOutboxWorkerDBMaxOpen,
			wantOverrideMaxOpen: 48,
			wantOverrideTimeout: 1250 * time.Millisecond,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name+"/defaults", func(t *testing.T) {
			cfg := tt.role.configFromEnv(func(string) string { return "" })
			if cfg.PoolOptions.MaxOpenConns != tt.wantDefaultMaxOpen {
				t.Fatalf("MaxOpenConns = %d, want %d", cfg.PoolOptions.MaxOpenConns, tt.wantDefaultMaxOpen)
			}
			if cfg.PoolOptions.MaxIdleConns != tt.wantDefaultMaxOpen {
				t.Fatalf("MaxIdleConns = %d, want %d", cfg.PoolOptions.MaxIdleConns, tt.wantDefaultMaxOpen)
			}
			if cfg.PingTimeout != tt.role.DefaultPingTimeout {
				t.Fatalf("PingTimeout = %s, want %s", cfg.PingTimeout, tt.role.DefaultPingTimeout)
			}
		})

		t.Run(tt.name+"/overrides", func(t *testing.T) {
			values := map[string]string{
				tt.role.MaxOpenEnv:     tt.overrideMaxOpen,
				tt.role.PingTimeoutEnv: tt.overridePingTimeout,
			}
			cfg := tt.role.configFromEnv(func(key string) string { return values[key] })
			if cfg.PoolOptions.MaxOpenConns != tt.wantOverrideMaxOpen {
				t.Fatalf("MaxOpenConns = %d, want %d", cfg.PoolOptions.MaxOpenConns, tt.wantOverrideMaxOpen)
			}
			if cfg.PoolOptions.MaxIdleConns != tt.wantOverrideMaxOpen {
				t.Fatalf("MaxIdleConns = %d, want %d", cfg.PoolOptions.MaxIdleConns, tt.wantOverrideMaxOpen)
			}
			if cfg.PingTimeout != tt.wantOverrideTimeout {
				t.Fatalf("PingTimeout = %s, want %s", cfg.PingTimeout, tt.wantOverrideTimeout)
			}
		})

		t.Run(tt.name+"/invalid values", func(t *testing.T) {
			values := map[string]string{
				tt.role.MaxOpenEnv:     "0",
				tt.role.PingTimeoutEnv: "-1s",
			}
			cfg := tt.role.configFromEnv(func(key string) string { return values[key] })
			if cfg.PoolOptions.MaxOpenConns != tt.wantDefaultMaxOpen {
				t.Fatalf("MaxOpenConns = %d, want default %d", cfg.PoolOptions.MaxOpenConns, tt.wantDefaultMaxOpen)
			}
			if cfg.PoolOptions.MaxIdleConns != tt.wantDefaultMaxOpen {
				t.Fatalf("MaxIdleConns = %d, want default %d", cfg.PoolOptions.MaxIdleConns, tt.wantDefaultMaxOpen)
			}
			if cfg.PingTimeout != tt.role.DefaultPingTimeout {
				t.Fatalf("PingTimeout = %s, want default %s", cfg.PingTimeout, tt.role.DefaultPingTimeout)
			}
		})
	}
}

func TestRuntimeDBPoolRolesPreserveStartupOrder(t *testing.T) {
	got := make([]string, 0, len(runtimeDBPoolRoles))
	for _, role := range runtimeDBPoolRoles {
		got = append(got, role.PoolName)
	}
	want := []string{
		connectorIngressDBPoolName,
		connectorPushDBPoolName,
		outboxWorkerDBPoolName,
	}
	if len(got) != len(want) {
		t.Fatalf("runtimeDBPoolRoles length = %d, want %d", len(got), len(want))
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("runtimeDBPoolRoles[%d] = %q, want %q", i, got[i], want[i])
		}
	}
}
