package cmd

import (
	"os"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/operator"
	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
)

func TestMain(m *testing.M) {
	resolveAgentTeamMachineAPIKey = func(serverURL string, apiKey string) (*agentteamAuthResolution, error) {
		return normalizeAgentTeamAuthResolution(serverURL, apiKey, &agentteamAuthResolution{
			MachineID:   "mac_1",
			APIKey:      apiKey,
			ServerURL:   serverURL,
			WorkspaceID: "wsp_1",
		})
	}
	os.Exit(m.Run())
}

func TestParseConnectURLAcceptsAuthLoginURL(t *testing.T) {
	token, serverURL, err := parseConnectURL("agentteam://auth/login?token=abc&origin=https%3A%2F%2Fagentteam.example.com")
	require.NoError(t, err)
	require.Equal(t, "abc", token)
	require.Equal(t, "https://agentteam.example.com", serverURL)
}

func TestResolveManualAgentTeamAuthDefaultsToSaaSServerURL(t *testing.T) {
	resolved, err := resolveManualAgentTeamAuth("", "key_1")
	require.NoError(t, err)
	require.Equal(t, defaultAgentTeamServerURL, resolved.ServerURL)
	require.Equal(t, "key_1", resolved.APIKey)
}

func TestUpsertAgentTeamAuthUpdatesExistingWorkspaceAuth(t *testing.T) {
	t.Parallel()

	existing := profileAgentTeamServerForTest("srv_existing", "https://agentteam.example.com", "wsp_1", "old-key")
	existing.ConnectionStatus = agentteamChannelStatusInvalidMachineAPIKey
	existing.Config = mapToRawMessage(map[string]interface{}{
		"server_url":        "https://agentteam.example.com",
		"workspace_id":      "wsp_1",
		"api_key":           "old-key",
		"connection_status": agentteamChannelStatusInvalidMachineAPIKey,
	})
	fakeChannels := &fakeChannelOperator{servers: []profile.AgentTeamServer{existing}}
	result, err := upsertAgentTeamAuth(fakeChannels, agentteamAuthResolution{
		ServerURL:   "https://agentteam.example.com/",
		WorkspaceID: "wsp_1",
		MachineID:   "mac_1",
		APIKey:      "new-key",
	})
	require.NoError(t, err)
	require.False(t, result.Created)
	require.Equal(t, "srv_existing", result.Server.ID)
	require.Len(t, fakeChannels.servers, 1)
	require.Equal(t, "new-key", agentteamChannelAPIKey(fakeChannels.servers[0]))
	require.Equal(t, "wsp_1", agentteamChannelWorkspaceID(fakeChannels.servers[0]))
	require.Equal(t, "mac_1", agentteamChannelMachineID(fakeChannels.servers[0]))
	require.Empty(t, result.Server.ConnectionStatus)
	require.Equal(t, "", configToMap(result.Server.Config)[agentteamChannelConfigKeyConnectionStatus])
}

func TestUpsertAgentTeamAuthAllowsSameServerDifferentWorkspaces(t *testing.T) {
	t.Parallel()

	fakeChannels := &fakeChannelOperator{servers: []profile.AgentTeamServer{
		profileAgentTeamServerForTest("srv_prod", "https://agentteam.example.com", "wsp_prod", "prod-key"),
	}}
	result, err := upsertAgentTeamAuth(fakeChannels, agentteamAuthResolution{
		ServerURL:   "https://agentteam.example.com",
		WorkspaceID: "wsp_dev",
		MachineID:   "mac_dev",
		APIKey:      "dev-key",
	})
	require.NoError(t, err)
	require.True(t, result.Created)
	require.Len(t, fakeChannels.servers, 2)
	require.Equal(t, "wsp_prod", agentteamChannelWorkspaceID(fakeChannels.servers[0]))
	require.Equal(t, "wsp_dev", agentteamChannelWorkspaceID(fakeChannels.servers[1]))
}

func TestRunAuthStatusReportsEmptyState(t *testing.T) {
	originalGetOperator := getOperator
	originalOpts := authStatusOpts
	t.Cleanup(func() {
		getOperator = originalGetOperator
		authStatusOpts = originalOpts
	})

	getOperator = func() (operator.Operator, error) {
		return fakeOperator{servers: &fakeChannelOperator{}}, nil
	}
	authStatusOpts.format = "table"

	var err error
	output := captureStdout(t, func() {
		err = runAuthStatus(authStatusCmd, nil)
	})

	require.NoError(t, err)
	require.Equal(t, "No AgentTeam auth found. Run: agentteam auth login --api-key <key>\n", output)
}

func TestRunAuthLogoutDeletesByID(t *testing.T) {
	originalGetOperator := getOperator
	originalOpts := authLogoutOpts
	t.Cleanup(func() {
		getOperator = originalGetOperator
		authLogoutOpts = originalOpts
	})

	fakeChannels := &fakeChannelOperator{servers: []profile.AgentTeamServer{
		profileAgentTeamServerForTest("srv_existing", "https://agentteam.example.com", "wsp_1", "key_1"),
	}}
	getOperator = func() (operator.Operator, error) {
		return fakeOperator{servers: fakeChannels}, nil
	}
	authLogoutOpts.all = false

	var err error
	output := captureStdout(t, func() {
		err = runAuthLogout(authLogoutCmd, []string{"srv_existing"})
	})

	require.NoError(t, err)
	require.Empty(t, fakeChannels.servers)
	require.Contains(t, output, "Logged out from AgentTeam.")
	require.Contains(t, output, "ID:        srv_existing")
	require.Contains(t, output, "Workspace: wsp_1")
}

func profileAgentTeamServerForTest(id string, serverURL string, workspaceID string, apiKey string) profile.AgentTeamServer {
	return profile.AgentTeamServer{
		ID:          id,
		Enabled:     true,
		ServerURL:   serverURL,
		WorkspaceID: workspaceID,
		APIKey:      apiKey,
		Config:      mapToRawMessage(connectedAgentTeamChannelConfig(serverURL, apiKey, workspaceID)),
	}
}
