package cmd

import (
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/daemon"
	"github.com/tidbcloud/AgentTeam/desktop/internal/daemoncontrol"
	"github.com/tidbcloud/AgentTeam/desktop/internal/operator"
)

func TestDesktopDeepLinkCommandIsHidden(t *testing.T) {
	require.True(t, desktopDeepLinkCmd.Hidden)
	require.Equal(t, "desktop-deep-link", desktopDeepLinkCmd.Use)
	for _, command := range rootCmd.Commands() {
		require.NotEqual(t, "app-launch", command.Name())
	}
}

func TestRunDesktopDeepLinkRequiresVerifiedHealthyDaemonBeforeParsingOrExchange(t *testing.T) {
	originalDaemonStatus := daemonStatus
	originalExchange := exchangeMachineConnectTokenForDesktopDeepLink
	originalGetOperator := getOperator
	originalInput := desktopDeepLinkInput
	t.Cleanup(func() {
		daemonStatus = originalDaemonStatus
		exchangeMachineConnectTokenForDesktopDeepLink = originalExchange
		getOperator = originalGetOperator
		desktopDeepLinkInput = originalInput
	})

	for _, status := range []*daemon.Status{
		{},
		{Running: true, Healthy: false, PID: 41},
		{
			Running:           true,
			Healthy:           true,
			PID:               42,
			DesktopAPIVersion: 0,
			BaseURL:           "http://127.0.0.1:43123",
		},
		{
			Running:           true,
			Healthy:           true,
			PID:               43,
			DesktopAPIVersion: daemoncontrol.DesktopAPIVersion,
		},
	} {
		t.Run(requireDaemonDescription(status), func(t *testing.T) {
			daemonStatus = func() *daemon.Status { return status }
			exchangeMachineConnectTokenForDesktopDeepLink = func(string, string) (*agentteamAuthResolution, error) {
				t.Fatal("unverified daemon must be rejected before token exchange")
				return nil, nil
			}
			getOperator = func() (operator.Operator, error) {
				t.Fatal("unverified daemon must be rejected before profile access")
				return nil, nil
			}

			desktopDeepLinkInput = strings.NewReader(
				"agentteam://connect?token=secret&origin=https%3A%2F%2Fagentteam.example.com",
			)
			err := runDesktopDeepLink(desktopDeepLinkCmd, nil)
			require.ErrorContains(t, err, "verified daemon is not ready")
			require.NotContains(t, err.Error(), "secret")
		})
	}
}

func TestRunDesktopDeepLinkExchangesAndUpsertsWithoutDaemonLifecycleActions(t *testing.T) {
	originalDaemonStatus := daemonStatus
	originalExchange := exchangeMachineConnectTokenForDesktopDeepLink
	originalGetOperator := getOperator
	originalRunDaemonForeground := runDaemonForeground
	originalStopUnhealthyProcess := stopUnhealthyProcess
	originalInput := desktopDeepLinkInput
	t.Cleanup(func() {
		daemonStatus = originalDaemonStatus
		exchangeMachineConnectTokenForDesktopDeepLink = originalExchange
		getOperator = originalGetOperator
		runDaemonForeground = originalRunDaemonForeground
		stopUnhealthyProcess = originalStopUnhealthyProcess
		desktopDeepLinkInput = originalInput
	})

	daemonStatus = func() *daemon.Status {
		return &daemon.Status{
			Running:           true,
			Healthy:           true,
			PID:               44,
			DesktopAPIVersion: daemoncontrol.DesktopAPIVersion,
			BaseURL:           "http://127.0.0.1:43123",
		}
	}
	var exchangedServer, exchangedToken string
	exchangeMachineConnectTokenForDesktopDeepLink = func(serverURL, token string) (*agentteamAuthResolution, error) {
		exchangedServer, exchangedToken = serverURL, token
		return &agentteamAuthResolution{
			MachineID:   "mac_1",
			APIKey:      "key_1",
			ServerURL:   serverURL,
			WorkspaceID: "wsp_1",
		}, nil
	}
	fakeServers := &fakeChannelOperator{}
	getOperator = func() (operator.Operator, error) {
		return fakeOperator{servers: fakeServers}, nil
	}
	runDaemonForeground = func() error {
		t.Fatal("desktop deep-link command must never start the daemon")
		return nil
	}
	stopUnhealthyProcess = func(int, time.Duration) error {
		t.Fatal("desktop deep-link command must never stop the daemon")
		return nil
	}

	desktopDeepLinkInput = strings.NewReader(
		"agentteam://auth/login?token=one-time-secret&origin=https%3A%2F%2Fagentteam.example.com",
	)
	require.NoError(t, runDesktopDeepLink(desktopDeepLinkCmd, nil))
	require.Equal(t, "https://agentteam.example.com", exchangedServer)
	require.Equal(t, "one-time-secret", exchangedToken)
	require.Len(t, fakeServers.servers, 1)
	cfg := configToMap(fakeServers.servers[0].Config)
	require.Equal(t, "wsp_1", cfg["workspace_id"])
}

func TestRunDesktopDeepLinkRejectsBadArityAndMalformedURLWithoutLeakingToken(t *testing.T) {
	originalDaemonStatus := daemonStatus
	originalInput := desktopDeepLinkInput
	t.Cleanup(func() {
		daemonStatus = originalDaemonStatus
		desktopDeepLinkInput = originalInput
	})
	daemonStatus = func() *daemon.Status {
		return &daemon.Status{
			Running:           true,
			Healthy:           true,
			PID:               45,
			DesktopAPIVersion: daemoncontrol.DesktopAPIVersion,
			BaseURL:           "http://127.0.0.1:43123",
		}
	}

	for _, input := range []string{
		"",
		"https://agentteam.example.com/connect?token=secret",
		"agentteam://connect?token=secret",
		strings.Repeat("x", maxDesktopDeepLinkBytes+1),
	} {
		desktopDeepLinkInput = strings.NewReader(input)
		err := runDesktopDeepLink(desktopDeepLinkCmd, nil)
		require.Error(t, err)
		require.NotContains(t, err.Error(), "secret")
	}
	desktopDeepLinkInput = strings.NewReader(
		"agentteam://connect?token=secret&origin=https%3A%2F%2Fagentteam.example.com",
	)
	err := runDesktopDeepLink(desktopDeepLinkCmd, []string{"unexpected"})
	require.Error(t, err)
	require.NotContains(t, err.Error(), "secret")
}

func TestRunDesktopDeepLinkUsesConnectExchangeContract(t *testing.T) {
	originalDaemonStatus := daemonStatus
	originalGetOperator := getOperator
	originalInput := desktopDeepLinkInput
	t.Cleanup(func() {
		daemonStatus = originalDaemonStatus
		getOperator = originalGetOperator
		desktopDeepLinkInput = originalInput
	})
	daemonStatus = func() *daemon.Status {
		return &daemon.Status{
			Running:           true,
			Healthy:           true,
			PID:               46,
			DesktopAPIVersion: daemoncontrol.DesktopAPIVersion,
			BaseURL:           "http://127.0.0.1:43123",
		}
	}

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		require.Equal(t, "/api/v1/machine-connect-exchanges", r.URL.Path)
		w.Header().Set("Content-Type", "application/json")
		_, _ = w.Write([]byte(`{"machineId":"mac_1","apiKey":"key_1","serverUrl":"","workspaceId":"wsp_1"}`))
	}))
	defer server.Close()
	fakeServers := &fakeChannelOperator{}
	getOperator = func() (operator.Operator, error) {
		return fakeOperator{servers: fakeServers}, nil
	}

	desktopDeepLinkInput = strings.NewReader(
		"agentteam://connect?token=tok_1&origin=" + url.QueryEscape(server.URL),
	)
	require.NoError(t, runDesktopDeepLink(desktopDeepLinkCmd, nil))
	require.Len(t, fakeServers.servers, 1)
}

func requireDaemonDescription(status *daemon.Status) string {
	if !status.Running {
		return "not-running"
	}
	if !status.Healthy {
		return "unhealthy"
	}
	if status.DesktopAPIVersion == 0 {
		return "missing-api-version"
	}
	return "missing-base-url"
}
