package runtimeconfig

import (
	"testing"

	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
)

func TestRuntimeEnvOverridesAddsLoopbackNoProxyForLocalMCP(t *testing.T) {
	t.Setenv("NO_PROXY", "corp.internal")
	t.Setenv("no_proxy", "existing.local")

	env := RuntimeEnvOverrides(map[string]string{
		"NO_PROXY": "runtime.internal",
	}, []types.NamedMCPConfig{
		{Name: "agentteam", URL: "http://127.0.0.1:8080/mcp/server/channel/agent"},
		{Name: "remote", URL: "https://example.com/mcp"},
	})

	if got := env["NO_PROXY"]; got != "runtime.internal,127.0.0.1,localhost,::1" {
		t.Fatalf("NO_PROXY = %q", got)
	}
	if got := env["no_proxy"]; got != "existing.local,127.0.0.1,localhost,::1" {
		t.Fatalf("no_proxy = %q", got)
	}
}

func TestRuntimeEnvOverridesHonorsOffMode(t *testing.T) {
	t.Setenv(mcpLocalNoProxyEnvVar, "off")
	t.Setenv("NO_PROXY", "corp.internal")

	env := RuntimeEnvOverrides(nil, []types.NamedMCPConfig{
		{Name: "agentteam", URL: "http://127.0.0.1:8080/mcp/server/channel/agent"},
	})

	if len(env) != 0 {
		t.Fatalf("env = %#v, want nil or empty", env)
	}
}

func TestRuntimeEnvOverridesHonorsOnMode(t *testing.T) {
	t.Setenv(mcpLocalNoProxyEnvVar, "on")
	t.Setenv("NO_PROXY", "corp.internal")
	t.Setenv("no_proxy", "corp.local")

	env := RuntimeEnvOverrides(nil, []types.NamedMCPConfig{
		{Name: "agentteam", URL: "https://example.com/mcp"},
	})

	if got := env["NO_PROXY"]; got != "corp.internal,127.0.0.1,localhost,::1" {
		t.Fatalf("NO_PROXY = %q", got)
	}
	if got := env["no_proxy"]; got != "corp.local,127.0.0.1,localhost,::1" {
		t.Fatalf("no_proxy = %q", got)
	}
}

func TestRuntimeEnvOverridesPrefersRuntimeOverrideMode(t *testing.T) {
	t.Setenv(mcpLocalNoProxyEnvVar, "off")
	t.Setenv("NO_PROXY", "")
	t.Setenv("no_proxy", "")

	env := RuntimeEnvOverrides(map[string]string{
		mcpLocalNoProxyEnvVar: "on",
	}, nil)

	if got := env["NO_PROXY"]; got != "127.0.0.1,localhost,::1" {
		t.Fatalf("NO_PROXY = %q", got)
	}
	if got := env["no_proxy"]; got != "127.0.0.1,localhost,::1" {
		t.Fatalf("no_proxy = %q", got)
	}
}

func TestRuntimeEnvOverridesDoesNotAddNoProxyForRemoteMCP(t *testing.T) {
	t.Setenv("NO_PROXY", "corp.internal")

	env := RuntimeEnvOverrides(map[string]string{
		"FOO": "bar",
	}, []types.NamedMCPConfig{
		{Name: "agentteam", URL: "https://example.com/mcp"},
	})

	if got := env["FOO"]; got != "bar" {
		t.Fatalf("FOO = %q", got)
	}
	if _, ok := env["NO_PROXY"]; ok {
		t.Fatalf("NO_PROXY unexpectedly set: %q", env["NO_PROXY"])
	}
	if _, ok := env["no_proxy"]; ok {
		t.Fatalf("no_proxy unexpectedly set: %q", env["no_proxy"])
	}
}

func TestRuntimeEnvOverridesClonesInput(t *testing.T) {
	base := map[string]string{"FOO": "bar"}
	env := RuntimeEnvOverrides(base, nil)
	env["FOO"] = "changed"

	if got := base["FOO"]; got != "bar" {
		t.Fatalf("base map mutated: %q", got)
	}
}

func TestRuntimeEnvOverridesWithLoopbackURLsAddsNoProxyForLocalProvider(t *testing.T) {
	t.Setenv("NO_PROXY", "corp.internal")
	t.Setenv("no_proxy", "corp.local")

	env := RuntimeEnvOverridesWithLoopbackURLs(map[string]string{
		"FOO": "bar",
	}, "http://127.0.0.1:39123/maas/v1", "https://maas.example.test/maas/v1")

	if got := env["FOO"]; got != "bar" {
		t.Fatalf("FOO = %q", got)
	}
	if got := env["NO_PROXY"]; got != "corp.internal,127.0.0.1,localhost,::1" {
		t.Fatalf("NO_PROXY = %q", got)
	}
	if got := env["no_proxy"]; got != "corp.local,127.0.0.1,localhost,::1" {
		t.Fatalf("no_proxy = %q", got)
	}
}

func TestRuntimeEnvOverridesWithLoopbackURLsLeavesRemoteProviderUntouched(t *testing.T) {
	env := RuntimeEnvOverridesWithLoopbackURLs(map[string]string{
		"FOO": "bar",
	}, "https://maas.example.test/maas/v1")

	if got := env["FOO"]; got != "bar" {
		t.Fatalf("FOO = %q", got)
	}
	if _, ok := env["NO_PROXY"]; ok {
		t.Fatalf("NO_PROXY unexpectedly set: %q", env["NO_PROXY"])
	}
	if _, ok := env["no_proxy"]; ok {
		t.Fatalf("no_proxy unexpectedly set: %q", env["no_proxy"])
	}
}

func TestLoopbackMCPHost(t *testing.T) {
	tests := []struct {
		name string
		url  string
		want string
	}{
		{name: "localhost", url: "http://localhost:8080/mcp", want: "localhost"},
		{name: "ipv4", url: "http://127.0.0.1:8080/mcp", want: "127.0.0.1"},
		{name: "ipv6", url: "http://[::1]:8080/mcp", want: "::1"},
		{name: "remote", url: "https://example.com/mcp", want: ""},
		{name: "invalid", url: "://bad", want: ""},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			if got := loopbackMCPHost(tc.url); got != tc.want {
				t.Fatalf("loopbackMCPHost(%q) = %q, want %q", tc.url, got, tc.want)
			}
		})
	}
}

func TestMergeNoProxyEntriesDeduplicatesCaseInsensitively(t *testing.T) {
	got := mergeNoProxyEntries("LOCALHOST,corp.internal", "localhost", "127.0.0.1", "corp.internal")
	if got != "LOCALHOST,corp.internal,127.0.0.1" {
		t.Fatalf("mergeNoProxyEntries() = %q", got)
	}
}

func TestRuntimeEnvOverridesUsesProcessNoProxyWhenRuntimeEnvIsEmpty(t *testing.T) {
	t.Setenv("NO_PROXY", "corp.internal")
	t.Setenv("no_proxy", "corp.local")

	env := RuntimeEnvOverrides(nil, []types.NamedMCPConfig{
		{Name: "agentteam", URL: "http://localhost:8080/mcp"},
	})

	if got := env["NO_PROXY"]; got != "corp.internal,127.0.0.1,localhost,::1" {
		t.Fatalf("NO_PROXY = %q", got)
	}
	if got := env["no_proxy"]; got != "corp.local,127.0.0.1,localhost,::1" {
		t.Fatalf("no_proxy = %q", got)
	}
}

func TestParseLoopbackNoProxyMode(t *testing.T) {
	tests := []struct {
		name  string
		input string
		want  loopbackNoProxyMode
	}{
		{name: "default", input: "", want: loopbackNoProxyAuto},
		{name: "auto", input: "auto", want: loopbackNoProxyAuto},
		{name: "on", input: "on", want: loopbackNoProxyOn},
		{name: "true", input: "true", want: loopbackNoProxyOn},
		{name: "off", input: "off", want: loopbackNoProxyOff},
		{name: "false", input: "false", want: loopbackNoProxyOff},
		{name: "invalid", input: "maybe", want: loopbackNoProxyAuto},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			if got := parseLoopbackNoProxyMode(tc.input); got != tc.want {
				t.Fatalf("parseLoopbackNoProxyMode(%q) = %v, want %v", tc.input, got, tc.want)
			}
		})
	}
}
