package services

import (
	"testing"

	"clawreef/internal/models"
)

func TestNormalizeEnvironmentOverrides(t *testing.T) {
	overrides, err := normalizeEnvironmentOverrides(map[string]string{
		" FOO ": "bar",
		"BAR_2": "",
	})
	if err != nil {
		t.Fatalf("normalizeEnvironmentOverrides returned error: %v", err)
	}

	if overrides["FOO"] != "bar" {
		t.Fatalf("expected trimmed key FOO to be preserved")
	}
	if value, ok := overrides["BAR_2"]; !ok || value != "" {
		t.Fatalf("expected empty override value to be preserved")
	}
}

func TestNormalizeEnvironmentOverridesRejectsInvalidNames(t *testing.T) {
	if _, err := normalizeEnvironmentOverrides(map[string]string{
		"1INVALID": "value",
	}); err == nil {
		t.Fatalf("expected invalid environment variable name to fail validation")
	}
}

func TestBuildInstancePodEnvAppliesOverridesAfterDefaults(t *testing.T) {
	t.Setenv("CLAWMANAGER_EGRESS_PROXY_URL", "")
	t.Setenv("CLAWMANAGER_SYSTEM_NAMESPACE", "")
	t.Setenv("K8S_NAMESPACE", "")

	raw, err := marshalEnvironmentOverrides(map[string]string{
		"SUBFOLDER":                "/custom-proxy",
		"KASM_SVC_ACCEPT_CUT_TEXT": "-AcceptCutText 1",
		"CUSTOM":                   "enabled",
	})
	if err != nil {
		t.Fatalf("marshalEnvironmentOverrides returned error: %v", err)
	}

	instance := &models.Instance{
		ID:                       42,
		Type:                     "webtop",
		EnvironmentOverridesJSON: raw,
	}

	env, err := buildInstancePodEnv(instance, map[string]string{
		"TITLE":     "ClawManager Webtop",
		"SUBFOLDER": "/",
	}, nil, nil)
	if err != nil {
		t.Fatalf("buildInstancePodEnv returned error: %v", err)
	}

	if env["SUBFOLDER"] != "/custom-proxy" {
		t.Fatalf("expected SUBFOLDER override to win, got %q", env["SUBFOLDER"])
	}
	if env["KASM_SVC_ACCEPT_CUT_TEXT"] != "-AcceptCutText 1" {
		t.Fatalf("expected clipboard policy override to win, got %q", env["KASM_SVC_ACCEPT_CUT_TEXT"])
	}
	if env["CUSTOM"] != "enabled" {
		t.Fatalf("expected custom environment variable to be merged")
	}
	if env["TITLE"] != "ClawManager Webtop" {
		t.Fatalf("expected default environment variable to remain available")
	}
}

func TestBuildInstancePodEnvNormalizesDesktopStreamProfile(t *testing.T) {
	raw, err := marshalEnvironmentOverrides(map[string]string{
		"CLAWMANAGER_DESKTOP_STREAM_PROFILE": "standard",
		"SELKIES_ENCODER":                    "x264enc",
		"SELKIES_FRAMERATE":                  "35",
		"SELKIES_H264_CRF":                   "34",
	})
	if err != nil {
		t.Fatalf("marshalEnvironmentOverrides returned error: %v", err)
	}

	env, err := buildInstancePodEnv(&models.Instance{
		ID:                       42,
		Type:                     "openclaw",
		RuntimeType:              RuntimeBackendDesktop,
		EnvironmentOverridesJSON: raw,
	}, nil, nil, nil)
	if err != nil {
		t.Fatalf("buildInstancePodEnv returned error: %v", err)
	}

	if got := env["SELKIES_ENCODER"]; got != "x264enc,jpeg" {
		t.Fatalf("SELKIES_ENCODER = %q, want x264enc,jpeg", got)
	}
	if got := env["SELKIES_USE_CSS_SCALING"]; got != "true" {
		t.Fatalf("SELKIES_USE_CSS_SCALING = %q, want true", got)
	}
}

func TestPopSHMSizeGB(t *testing.T) {
	tests := []struct {
		name     string
		value    string
		hasValue bool
		runtime  string
		memoryGB int
		want     int
	}{
		{name: "desktop minimum preset", runtime: "desktop", memoryGB: 4, want: defaultInstanceSHMSizeGB},
		{name: "desktop medium preset", runtime: "desktop", memoryGB: 8, want: 2},
		{name: "desktop large preset", runtime: "desktop", memoryGB: 12, want: 4},
		{name: "desktop small fallback", runtime: "desktop", memoryGB: 2, want: defaultInstanceSHMSizeGB},
		{name: "shell default unchanged", runtime: "shell", memoryGB: 8, want: defaultInstanceSHMSizeGB},
		{name: "disable", value: "0", hasValue: true, runtime: "desktop", memoryGB: 8, want: 0},
		{name: "custom", value: "4", hasValue: true, runtime: "desktop", memoryGB: 4, want: 4},
		{name: "clamp", value: "128", hasValue: true, runtime: "desktop", memoryGB: 8, want: maxInstanceSHMSizeGB},
		{name: "invalid keeps dynamic desktop default", value: "nope", hasValue: true, runtime: "desktop", memoryGB: 8, want: 2},
		{name: "negative keeps dynamic desktop default", value: "-1", hasValue: true, runtime: "desktop", memoryGB: 4, want: defaultInstanceSHMSizeGB},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			extraEnv := map[string]string{"KEEP": "value"}
			if tt.hasValue {
				extraEnv["SHM_SIZE_GB"] = tt.value
			}

			got := popSHMSizeGB(extraEnv, tt.runtime, tt.memoryGB)
			if got != tt.want {
				t.Fatalf("expected shm size %d, got %d", tt.want, got)
			}
			if _, ok := extraEnv["SHM_SIZE_GB"]; ok {
				t.Fatalf("expected SHM_SIZE_GB to be removed from extra env")
			}
			if extraEnv["KEEP"] != "value" {
				t.Fatalf("expected unrelated env to be preserved")
			}
		})
	}
}
