package profile

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/runtimeconfig"
)

func TestMCPServerManagerPersistsSecretRegistryWith0600Mode(t *testing.T) {
	dir := t.TempDir()
	t.Setenv(ConfigDirEnvKey, dir)
	mgr := New(dir)

	stored, err := mgr.MCPServers().Add(MCPServer{
		ID:          "zap_http",
		DisplayName: "Zap HTTP",
		Enabled:     true,
		Transport:   MCPServerTransportHTTP,
		HTTP:        &MCPHTTPConfig{URL: "https://mcp.example.com/rpc", Headers: []string{"Authorization: Bearer secret-token"}},
	})
	require.NoError(t, err)
	require.Equal(t, "zap_http", stored.ID)

	path := filepath.Join(dir, mcpServersFileName)
	info, err := os.Stat(path)
	require.NoError(t, err)
	require.Equal(t, os.FileMode(0o600), info.Mode().Perm())

	text, err := os.ReadFile(path)
	require.NoError(t, err)
	require.Contains(t, string(text), "Bearer secret-token")

	redacted := stored.Redacted()
	require.Empty(t, redacted.HTTP.Headers)
}

func TestMCPServerManagerUpdatePreservesConfig(t *testing.T) {
	dir := t.TempDir()
	t.Setenv(ConfigDirEnvKey, dir)
	mgr := New(dir)

	_, err := mgr.MCPServers().Add(MCPServer{
		ID:          "zap_http",
		DisplayName: "Zap HTTP",
		Enabled:     true,
		Transport:   MCPServerTransportHTTP,
		HTTP:        &MCPHTTPConfig{URL: "https://mcp.example.com/rpc", Headers: []string{"Authorization: Bearer old-token"}},
	})
	require.NoError(t, err)

	updated, err := mgr.MCPServers().Update("zap_http", MCPServer{
		DisplayName: "Zap HTTP renamed",
		Enabled:     true,
		Transport:   MCPServerTransportHTTP,
		HTTP:        &MCPHTTPConfig{URL: "https://mcp.example.com/rpc", Headers: []string{"Authorization: Bearer old-token"}},
	})
	require.NoError(t, err)
	require.Equal(t, "Zap HTTP renamed", updated.DisplayName)

	text, err := os.ReadFile(filepath.Join(dir, mcpServersFileName))
	require.NoError(t, err)
	require.Contains(t, string(text), "Bearer old-token")
}

func TestMCPServerValidationRejectsReservedIDsAndInvalidInputs(t *testing.T) {
	t.Run("reserved id", func(t *testing.T) {
		err := (MCPServer{ID: "agentteam", DisplayName: "AgentTeam", Enabled: true, Transport: MCPServerTransportHTTP, HTTP: &MCPHTTPConfig{URL: "http://example.com"}}).Validate()
		require.ErrorContains(t, err, "reserved")
	})

	t.Run("invalid header", func(t *testing.T) {
		err := (MCPServer{ID: "custom_http", DisplayName: "Custom", Enabled: true, Transport: MCPServerTransportHTTP, HTTP: &MCPHTTPConfig{URL: "http://example.com", Headers: []string{"Bad Header: x"}}}).Validate()
		require.ErrorContains(t, err, "header name")
	})

	t.Run("header missing colon", func(t *testing.T) {
		err := (MCPServer{ID: "custom_http2", DisplayName: "Custom", Enabled: true, Transport: MCPServerTransportHTTP, HTTP: &MCPHTTPConfig{URL: "http://example.com", Headers: []string{"NoColon"}}}).Validate()
		require.ErrorContains(t, err, "must contain ':'")
	})

	t.Run("duplicate header", func(t *testing.T) {
		err := (MCPServer{ID: "dup_hdr", DisplayName: "Dup", Enabled: true, Transport: MCPServerTransportHTTP, HTTP: &MCPHTTPConfig{URL: "http://example.com", Headers: []string{"X-Custom: a", "x-custom: b"}}}).Validate()
		require.ErrorContains(t, err, "duplicated")
	})

	t.Run("invalid cwd", func(t *testing.T) {
		err := (MCPServer{ID: "stdio_one", DisplayName: "Stdio", Enabled: true, Transport: MCPServerTransportStdio, Stdio: &MCPStdioConfig{Command: "tool", CWD: filepath.Join(t.TempDir(), "missing")}}).Validate()
		require.ErrorContains(t, err, "stdio cwd")
	})

	t.Run("env missing equals", func(t *testing.T) {
		err := (MCPServer{ID: "bad_env", DisplayName: "Bad", Enabled: true, Transport: MCPServerTransportStdio, Stdio: &MCPStdioConfig{Command: "tool", Env: []string{"NOEQUALS"}}}).Validate()
		require.ErrorContains(t, err, "must contain '='")
	})

	t.Run("duplicate env", func(t *testing.T) {
		err := (MCPServer{ID: "dup_env", DisplayName: "Dup", Enabled: true, Transport: MCPServerTransportStdio, Stdio: &MCPStdioConfig{Command: "tool", Env: []string{"FOO=bar", "FOO=baz"}}}).Validate()
		require.ErrorContains(t, err, "duplicated")
	})
}

func TestMCPResolvedEnvExpandsEnvVars(t *testing.T) {
	t.Setenv("TEST_MCP_KEY", "expanded-value")
	cfg := MCPStdioConfig{Command: "echo", Env: []string{
		"STATIC=plain",
		"DYNAMIC=$TEST_MCP_KEY",
	}}
	result := cfg.ResolvedEnv()
	require.Equal(t, []string{"STATIC=plain", "DYNAMIC=expanded-value"}, result)
}

func TestExpandRuntimeEnvUsesShellSnapshot(t *testing.T) {
	runtimeconfig.SetShellEnvForRuntimeResolution(map[string]string{
		"TEST_MCP_SHELL_KEY": "shell-value",
	})
	t.Cleanup(func() {
		runtimeconfig.SetShellEnvForRuntimeResolution(nil)
	})

	require.Equal(t, "value=shell-value", ExpandRuntimeEnv("value=$TEST_MCP_SHELL_KEY"))
}

func TestMCPResolveHeadersExpandsEnvVars(t *testing.T) {
	t.Setenv("TEST_MCP_TOKEN", "Bearer resolved")
	cfg := MCPHTTPConfig{URL: "http://example.com", Headers: []string{
		"X-Static: fixed",
		"Authorization: $TEST_MCP_TOKEN",
	}}
	result := cfg.ResolveHeaders()
	require.Equal(t, []string{"X-Static: fixed", "Authorization: Bearer resolved"}, result)
}

func TestMCPServerManagerRoundTripsNewFormat(t *testing.T) {
	dir := t.TempDir()
	t.Setenv(ConfigDirEnvKey, dir)
	mgr := New(dir)

	_, err := mgr.MCPServers().Add(MCPServer{
		ID:          "http_one",
		DisplayName: "HTTP One",
		Enabled:     true,
		Transport:   MCPServerTransportHTTP,
		HTTP:        &MCPHTTPConfig{URL: "https://mcp.example.com", Headers: []string{"Authorization: Bearer tok1", "X-Custom: val"}},
	})
	require.NoError(t, err)

	_, err = mgr.MCPServers().Add(MCPServer{
		ID:          "stdio_one",
		DisplayName: "Stdio One",
		Enabled:     true,
		Transport:   MCPServerTransportStdio,
		Stdio:       &MCPStdioConfig{Command: "/bin/echo", Env: []string{"FOO=bar", "BAZ=$DNE"}},
	})
	require.NoError(t, err)

	mgr.ReloadMCPServers()
	all := mgr.MCPServers().All()
	require.Len(t, all, 2)
	require.Equal(t, "http_one", all[0].ID)
	require.Equal(t, []string{"Authorization: Bearer tok1", "X-Custom: val"}, all[0].HTTP.Headers)
	require.Equal(t, "stdio_one", all[1].ID)
	require.Equal(t, []string{"FOO=bar", "BAZ=$DNE"}, all[1].Stdio.Env)
}
