package machine

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent"
	"github.com/tidbcloud/AgentTeam/desktop/internal/api/auth"
	"github.com/tidbcloud/AgentTeam/desktop/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/desktop/internal/api/session"
	"github.com/tidbcloud/AgentTeam/desktop/internal/diagnosticbundle"
	"github.com/tidbcloud/AgentTeam/desktop/internal/metrics"
	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
	"github.com/tidbcloud/AgentTeam/desktop/internal/uisession"
	"github.com/tidbcloud/AgentTeam/desktop/internal/userauth"
)

const maxServerResponseBytes = 2 << 20

const desktopMachineConnectionTimeout = 15 * time.Second

const legacyBindingRecoveryRequiredCode = "DESKTOP_MACHINE_BINDING_RECOVERY_REQUIRED"

var errLegacyBindingRecoveryRequired = errors.New("the saved Desktop connection could not be verified; restore an existing Machine or confirm replacement")

type Handler struct {
	service          *Service
	sessions         *uisession.Store
	agentSessions    session.SessionsStore
	dashboardMetrics DashboardMetrics
	tokenTracking    metrics.TokenSourceQuerier
}

// GetDashboard returns the old Dashboard message/token contracts as one
// Machine-scoped bundle for the active Workspace's current Desktop. Browser
// builds never call this local endpoint.
func (handler *Handler) GetDashboard(c *gin.Context) {
	target, ok := handler.activeTarget(c, strings.TrimSpace(c.Query("workspaceId")))
	if !ok {
		return
	}
	machineID := strings.TrimSpace(c.Param("machineId"))
	if machineID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "machineId is required"})
		return
	}
	localServer, ok := handler.service.currentBindingServer(target, machineID)
	if !ok {
		c.JSON(http.StatusConflict, gin.H{"error": "This Machine is not the current Desktop"})
		return
	}
	window, err := parseDashboardWindow(c.DefaultQuery("window", "1d"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	configuredAgents := handler.service.agentsForServer(localServer.ID)
	configuredByID := make(map[string]agent.Config, len(configuredAgents))
	for _, configured := range configuredAgents {
		configuredByID[configured.ID] = configured
	}
	selectedAgentIDs := c.QueryArray("agentId")
	if len(selectedAgentIDs) > 0 {
		configuredAgents = make([]agent.Config, 0, len(selectedAgentIDs))
		seen := make(map[string]struct{}, len(selectedAgentIDs))
		for _, agentID := range selectedAgentIDs {
			agentID = strings.TrimSpace(agentID)
			if agentID == "" {
				continue
			}
			if _, exists := seen[agentID]; exists {
				continue
			}
			configured, exists := configuredByID[agentID]
			if !exists {
				c.JSON(http.StatusBadRequest, gin.H{"error": "agentId does not belong to the current Desktop Machine"})
				return
			}
			seen[agentID] = struct{}{}
			configuredAgents = append(configuredAgents, configured)
		}
		if len(configuredAgents) == 0 {
			c.JSON(http.StatusBadRequest, gin.H{"error": "at least one valid agentId is required"})
			return
		}
	}
	agentIDs := make([]string, 0, len(configuredAgents))
	for _, configured := range configuredAgents {
		agentIDs = append(agentIDs, configured.ID)
	}
	collector := handler.dashboardMetrics
	if collector == nil {
		collector = metrics.DefaultServerMessageCollector()
	}
	aggregate := metrics.AgentDashboardMetrics{
		MessageTrend: metrics.ServerMessageDirectionalTimeSeriesResponse{
			Interval: int(metrics.MachineDashboardOverviewAggregationInterval(window).Seconds()),
			Data:     []metrics.ServerMessageDirectionalTimeSeriesPoint{},
		},
		TokenTrend: metrics.AgentTokenTimeSeriesResponse{
			Interval: int(metrics.MachineDashboardOverviewAggregationInterval(window).Seconds()),
			Data:     []metrics.TimeSeriesDataPoint{},
		},
		MessageBar:     metrics.BarSeriesResponse{Interval: int(metrics.MachineDashboardOverviewAggregationInterval(window).Seconds()), Series: []metrics.BarSeriesEntry{{Key: "inbound", Label: "Inbound"}, {Key: "outbound", Label: "Outbound"}}, Data: []metrics.BarSeriesPoint{}},
		InputTokenBar:  metrics.BarSeriesResponse{Interval: int(metrics.MachineDashboardOverviewAggregationInterval(window).Seconds()), Series: []metrics.BarSeriesEntry{}, Data: []metrics.BarSeriesPoint{}},
		CachedTokenBar: metrics.BarSeriesResponse{Interval: int(metrics.MachineDashboardOverviewAggregationInterval(window).Seconds()), Series: []metrics.BarSeriesEntry{}, Data: []metrics.BarSeriesPoint{}},
		OutputTokenBar: metrics.BarSeriesResponse{Interval: int(metrics.MachineDashboardOverviewAggregationInterval(window).Seconds()), Series: []metrics.BarSeriesEntry{}, Data: []metrics.BarSeriesPoint{}},
		Agents:         []metrics.AgentDashboardRow{},
	}
	if collector != nil {
		aggregate = collector.QueryAgentsDashboard(agentIDs, window)
	}
	tokenSources := metrics.UnavailableTokenSourceResult(window)
	tokenTracking := handler.tokenTracking
	if tokenTracking == nil {
		tokenTracking = metrics.DefaultTokenTrackingQuerier()
	}
	if tokenTracking != nil {
		tokenSources = tokenTracking.QueryTokenTracking(metrics.TokenSourceQuery{
			AgentIDs: agentIDs,
			Window:   window,
		})
	}
	rowsByID := make(map[string]metrics.AgentDashboardRow, len(aggregate.Agents))
	for _, row := range aggregate.Agents {
		rowsByID[row.AgentID] = row
	}
	activeIDs := make(map[string]struct{})
	if handler.agentSessions != nil {
		for _, snapshot := range handler.agentSessions.Sessions() {
			activeIDs[strings.TrimSpace(snapshot.AgentConfigID)] = struct{}{}
			activeIDs[strings.TrimSpace(snapshot.AgentID)] = struct{}{}
		}
	}
	agents := make([]dto.DesktopMachineDashboardAgent, 0, len(configuredAgents))
	activeCount := 0
	for _, configured := range configuredAgents {
		row := rowsByID[configured.ID]
		_, active := activeIDs[configured.ID]
		if active {
			activeCount++
		}
		agents = append(agents, dto.DesktopMachineDashboardAgent{
			AgentID:  configured.ID,
			Name:     configured.Name,
			Runtime:  configured.Runtime,
			Active:   active,
			Received: row.Received,
			Sent:     row.Sent,
			Input:    row.Input,
			Cached:   row.Cached,
			Output:   row.Output,
			Total:    row.Total,
		})
	}
	c.JSON(http.StatusOK, dto.DesktopMachineDashboardResponse{
		MachineID:      machineID,
		WorkspaceID:    target.WorkspaceID,
		Window:         window.String(),
		AgentCount:     len(agents),
		ActiveAgents:   activeCount,
		MessageSummary: aggregate.MessageSummary,
		MessageTrend:   aggregate.MessageTrend,
		MessageBar:     aggregate.MessageBar,
		TokenSummary:   aggregate.TokenSummary,
		TokenTrend:     aggregate.TokenTrend,
		InputTokenBar:  aggregate.InputTokenBar,
		CachedTokenBar: aggregate.CachedTokenBar,
		OutputTokenBar: aggregate.OutputTokenBar,
		TokenSources:   tokenSources,
		Agents:         agents,
	})
}

func parseDashboardWindow(value string) (metrics.TimeWindow, error) {
	switch strings.TrimSpace(value) {
	case "6h":
		return metrics.TimeWindow6Hours, nil
	case "12h":
		return metrics.TimeWindow12Hours, nil
	case "1d":
		return metrics.TimeWindow1Day, nil
	case "3d":
		return metrics.TimeWindow3Days, nil
	case "1w":
		return metrics.TimeWindow1Week, nil
	default:
		return 0, fmt.Errorf("invalid time window, must be one of: 6h, 12h, 1d, 3d, 1w")
	}
}

func (service *Service) currentBindingServer(target userauth.Target, machineID string) (profile.AgentTeamServer, bool) {
	for _, server := range service.bindingServers(target) {
		if strings.TrimSpace(server.MachineID) == strings.TrimSpace(machineID) {
			return server, true
		}
	}
	return profile.AgentTeamServer{}, false
}

func (service *Service) agentsForServer(serverID string) []agent.Config {
	if service == nil || service.agents == nil {
		return nil
	}
	all := service.agents.All()
	result := make([]agent.Config, 0, len(all))
	for _, configured := range all {
		if configured.Source.Type == "agentteam" && strings.TrimSpace(configured.Source.ID) == strings.TrimSpace(serverID) {
			result = append(result, configured)
		}
	}
	return result
}

type Service struct {
	auth                *userauth.Manager
	agents              *profile.AgentManager
	connectionReadiness ConnectionReadiness
	diagnosticPaths     diagnosticbundle.Paths
	servers             *profile.ServerManager
	mu                  sync.Mutex
}

type serverMachine struct {
	ID string `json:"id"`
}

type serverMachineList struct {
	Machines []serverMachine `json:"machines"`
}

type serverMachineCreateResponse struct {
	Machine serverMachine `json:"machine"`
	APIKey  string        `json:"apiKey"`
}

type serverMachineAuthResolution struct {
	MachineID   string `json:"machineId"`
	ServerURL   string `json:"serverUrl"`
	WorkspaceID string `json:"workspaceId"`
}

type serverMachineConnectTokenResponse struct {
	Token string `json:"token"`
}

type serverMachineConnectExchangeResponse struct {
	MachineID   string `json:"machineId"`
	APIKey      string `json:"apiKey"`
	ServerURL   string `json:"serverUrl"`
	WorkspaceID string `json:"workspaceId"`
}

// EnsureFirstBinding activates the current computer only when the selected
// Workspace has no server-side Machines. It is safe to call from both manual
// onboarding activation and last-Workspace restoration.
func (service *Service) EnsureFirstBinding(ctx context.Context, targetID string) (profile.MachineBinding, int, error) {
	if service == nil || service.auth == nil {
		return profile.MachineBinding{}, http.StatusServiceUnavailable, fmt.Errorf("Desktop machine setup is unavailable")
	}
	target, ok := service.auth.Target(strings.TrimSpace(targetID))
	if !ok {
		return profile.MachineBinding{}, http.StatusConflict, fmt.Errorf("the active Desktop login is unavailable")
	}
	binding, _, status, err := service.EnsureCurrentBinding(ctx, target, true)
	return binding, status, err
}

// GetCurrentBinding handles GET /api/internal/machines/current-binding.
// It reports whether this Desktop already owns the selected Workspace binding.
func (handler *Handler) GetCurrentBinding(c *gin.Context) {
	target, ok := handler.activeTarget(c, strings.TrimSpace(c.Query("workspaceId")))
	if !ok {
		return
	}
	binding, exists, upstreamStatus, err := handler.service.ReconcileCurrentBinding(c.Request.Context(), target)
	if err != nil {
		if errors.Is(err, errLegacyBindingRecoveryRequired) {
			c.JSON(http.StatusOK, dto.DesktopCurrentMachineBindingResponse{Status: "recovery_required"})
			return
		}
		writeUpstreamError(c, upstreamStatus, err)
		return
	}
	status := "available"
	if exists {
		status = "added"
	}
	c.JSON(http.StatusOK, dto.DesktopCurrentMachineBindingResponse{
		MachineID: binding.MachineID,
		Status:    status,
	})
}

// CreateCurrentBinding handles POST /api/internal/machines/current-bindings.
// It creates and connects this Desktop. Machine credentials never cross the
// local HTTP response boundary.
func (handler *Handler) CreateCurrentBinding(c *gin.Context) {
	var request dto.DesktopCurrentMachineBindingRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "workspaceId is required"})
		return
	}
	target, ok := handler.activeTarget(c, request.WorkspaceID)
	if !ok {
		return
	}
	var binding profile.MachineBinding
	var created bool
	var status int
	var err error
	if request.ReplaceUnresolved {
		binding, created, status, err = handler.service.ReplaceUnresolvedCurrentBinding(c.Request.Context(), target)
	} else {
		binding, created, status, err = handler.service.EnsureCurrentBinding(c.Request.Context(), target, false)
	}
	if err != nil {
		writeUpstreamError(c, status, err)
		return
	}
	resultStatus := "added"
	if created {
		resultStatus = "created"
	}
	c.JSON(http.StatusOK, dto.DesktopCurrentMachineBindingResponse{
		MachineID: binding.MachineID,
		Status:    resultStatus,
	})
}

// RestoreCurrentBinding handles POST /api/internal/machines/current-bindings/restore.
// It reconnects this Desktop to an existing server Machine without exposing the
// resolved machine credential to the Web UI.
func (handler *Handler) RestoreCurrentBinding(c *gin.Context) {
	var request dto.DesktopRestoreMachineBindingRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "workspaceId and machineId are required"})
		return
	}
	target, ok := handler.activeTarget(c, request.WorkspaceID)
	if !ok {
		return
	}
	binding, status, err := handler.service.RestoreCurrentBinding(c.Request.Context(), target, request.MachineID)
	if err != nil {
		writeUpstreamError(c, status, err)
		return
	}
	c.JSON(http.StatusOK, dto.DesktopCurrentMachineBindingResponse{
		MachineID: binding.MachineID,
		Status:    "restored",
	})
}

func (handler *Handler) activeTarget(c *gin.Context, workspaceID string) (userauth.Target, bool) {
	sessionID, _, ok := auth.SessionIdentity(c)
	if !ok || handler.sessions == nil || handler.service == nil || handler.service.auth == nil || handler.service.servers == nil {
		c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Desktop machine setup is unavailable"})
		return userauth.Target{}, false
	}
	snapshot, ok := handler.sessions.Get(sessionID)
	if !ok || strings.TrimSpace(snapshot.ActiveServerID) == "" {
		c.JSON(http.StatusConflict, gin.H{"error": "Select a Workspace before setting up this Desktop"})
		return userauth.Target{}, false
	}
	target, ok := handler.service.auth.Target(snapshot.ActiveServerID)
	if !ok {
		c.JSON(http.StatusConflict, gin.H{"error": "The active Desktop login is unavailable"})
		return userauth.Target{}, false
	}
	workspaceID = strings.TrimSpace(workspaceID)
	if workspaceID == "" || workspaceID != target.WorkspaceID {
		c.JSON(http.StatusConflict, gin.H{"error": "The active Workspace changed before machine setup began"})
		return userauth.Target{}, false
	}
	return target, true
}

func (service *Service) bindingServers(target userauth.Target) []profile.AgentTeamServer {
	if service == nil || service.servers == nil {
		return nil
	}
	serverURL := strings.TrimRight(strings.TrimSpace(target.ServerURL), "/")
	var enabled []profile.AgentTeamServer
	var disabled []profile.AgentTeamServer
	for _, server := range service.servers.All() {
		if strings.TrimRight(strings.TrimSpace(server.ServerURL), "/") == serverURL &&
			strings.TrimSpace(server.WorkspaceID) == strings.TrimSpace(target.WorkspaceID) &&
			strings.TrimSpace(server.MachineID) != "" && strings.TrimSpace(server.APIKey) != "" {
			if server.Enabled {
				enabled = append(enabled, server)
			} else {
				disabled = append(disabled, server)
			}
		}
	}
	return append(enabled, disabled...)
}

// ReconcileCurrentBinding treats AgentTeam Server as the authority for persisted
// machine credentials. Invalid or identity-mismatched entries are removed
// through ServerManager so the running daemon disconnects them transactionally.
func (service *Service) ReconcileCurrentBinding(ctx context.Context, target userauth.Target) (profile.MachineBinding, bool, int, error) {
	service.mu.Lock()
	defer service.mu.Unlock()
	return service.reconcileCurrentBindingLocked(ctx, target, false)
}

// RestoreCurrentBinding resolves a fresh credential for an existing server-side
// Machine and persists it as the current Desktop binding.
func (service *Service) RestoreCurrentBinding(ctx context.Context, target userauth.Target, machineID string) (profile.MachineBinding, int, error) {
	service.mu.Lock()
	defer service.mu.Unlock()

	if service == nil || service.auth == nil || service.servers == nil {
		return profile.MachineBinding{}, http.StatusServiceUnavailable, fmt.Errorf("Desktop machine setup is unavailable")
	}
	machineID = strings.TrimSpace(machineID)
	if machineID == "" {
		return profile.MachineBinding{}, http.StatusBadRequest, fmt.Errorf("machineId is required")
	}
	client, ok := service.auth.HTTPClient(target.AuthID)
	if !ok || client == nil {
		return profile.MachineBinding{}, http.StatusBadGateway, fmt.Errorf("the active AgentTeam Server is unavailable")
	}
	accessToken, err := service.auth.UserToken(ctx, target.AuthID)
	if err != nil {
		return profile.MachineBinding{}, http.StatusBadGateway, fmt.Errorf("unable to authenticate with the active AgentTeam Server")
	}

	serverURL := strings.TrimRight(strings.TrimSpace(target.ServerURL), "/")
	workspaceID := strings.TrimSpace(target.WorkspaceID)
	tokenEndpoint := serverURL + "/api/v1/workspaces/" + url.PathEscape(workspaceID) + "/machines/" + url.PathEscape(machineID) + "/connect-tokens"
	var tokenResponse serverMachineConnectTokenResponse
	status, err := doServerJSON(ctx, client, http.MethodPost, tokenEndpoint, map[string]string{
		"serverUrl": serverURL,
	}, accessToken, &tokenResponse)
	if status == http.StatusUnauthorized {
		accessToken, err = service.auth.RefreshUserToken(ctx, target.AuthID, accessToken)
		if err == nil {
			status, err = doServerJSON(ctx, client, http.MethodPost, tokenEndpoint, map[string]string{
				"serverUrl": serverURL,
			}, accessToken, &tokenResponse)
		}
	}
	if err != nil {
		return profile.MachineBinding{}, status, err
	}
	token := strings.TrimSpace(tokenResponse.Token)
	if token == "" {
		return profile.MachineBinding{}, http.StatusBadGateway, fmt.Errorf("AgentTeam Server returned an invalid Machine connect token")
	}

	exchangeEndpoint := serverURL + "/api/v1/machine-connect-exchanges"
	var exchange serverMachineConnectExchangeResponse
	status, err = doServerJSON(ctx, client, http.MethodPost, exchangeEndpoint, map[string]string{
		"token": token,
	}, "", &exchange)
	if err != nil {
		return profile.MachineBinding{}, status, err
	}

	binding := profile.MachineBinding{
		ServerURL:   strings.TrimRight(strings.TrimSpace(exchange.ServerURL), "/"),
		WorkspaceID: strings.TrimSpace(exchange.WorkspaceID),
		MachineID:   strings.TrimSpace(exchange.MachineID),
		APIKey:      strings.TrimSpace(exchange.APIKey),
	}
	if binding.ServerURL == "" {
		binding.ServerURL = serverURL
	}
	if binding.MachineID != machineID || binding.WorkspaceID != workspaceID || binding.APIKey == "" {
		return profile.MachineBinding{}, http.StatusBadGateway, fmt.Errorf("AgentTeam Server returned an invalid Machine credential")
	}

	persisted, err := service.servers.UpsertMachineBinding(binding)
	if err != nil {
		return profile.MachineBinding{}, http.StatusInternalServerError, fmt.Errorf("unable to reconnect this Desktop to the Workspace")
	}
	if status, err := service.waitForServerConnection(ctx, persisted.ID); err != nil {
		return profile.MachineBinding{}, status, err
	}
	return binding, http.StatusOK, nil
}

// EnsureCurrentBinding reuses the existing deep-link destination operation:
// create a server Machine and persist its resolved daemon credential locally.
// When onlyIfUserHasNoMachines is true, an existing Machine owned by the
// current user is left alone.
func (service *Service) EnsureCurrentBinding(ctx context.Context, target userauth.Target, onlyIfUserHasNoMachines bool) (profile.MachineBinding, bool, int, error) {
	service.mu.Lock()
	defer service.mu.Unlock()
	return service.ensureCurrentBindingLocked(ctx, target, onlyIfUserHasNoMachines, false)
}

// ReplaceUnresolvedCurrentBinding creates a replacement only after the Desktop
// UI has explicitly confirmed abandoning an unverifiable compatibility entry.
func (service *Service) ReplaceUnresolvedCurrentBinding(ctx context.Context, target userauth.Target) (profile.MachineBinding, bool, int, error) {
	service.mu.Lock()
	defer service.mu.Unlock()
	return service.ensureCurrentBindingLocked(ctx, target, false, true)
}

func (service *Service) ensureCurrentBindingLocked(ctx context.Context, target userauth.Target, onlyIfUserHasNoMachines, replaceUnresolved bool) (profile.MachineBinding, bool, int, error) {
	binding, exists, status, err := service.reconcileCurrentBindingLocked(ctx, target, replaceUnresolved)
	if err != nil {
		return profile.MachineBinding{}, false, status, err
	}
	if exists {
		if status, err := service.waitForCurrentMachine(ctx, target, binding); err != nil {
			return profile.MachineBinding{}, false, status, err
		}
		return binding, false, http.StatusOK, nil
	}
	workspaceID := strings.TrimSpace(target.WorkspaceID)

	client, ok := service.auth.HTTPClient(target.AuthID)
	if !ok || client == nil {
		return profile.MachineBinding{}, false, http.StatusBadGateway, fmt.Errorf("the active AgentTeam Server is unavailable")
	}
	accessToken, err := service.auth.UserToken(ctx, target.AuthID)
	if err != nil {
		return profile.MachineBinding{}, false, http.StatusBadGateway, fmt.Errorf("unable to authenticate with the active AgentTeam Server")
	}

	machinesPath := "/api/v1/workspaces/" + url.PathEscape(workspaceID) + "/machines"
	if onlyIfUserHasNoMachines {
		listEndpoint := strings.TrimRight(target.ServerURL, "/") + machinesPath + "?scope=own&limit=1"
		var machineList serverMachineList
		status, listErr := doServerJSON(ctx, client, http.MethodGet, listEndpoint, nil, accessToken, &machineList)
		if status == http.StatusUnauthorized {
			accessToken, listErr = service.auth.RefreshUserToken(ctx, target.AuthID, accessToken)
			if listErr == nil {
				status, listErr = doServerJSON(ctx, client, http.MethodGet, listEndpoint, nil, accessToken, &machineList)
			}
		}
		if listErr != nil {
			return profile.MachineBinding{}, false, status, listErr
		}
		if len(machineList.Machines) > 0 {
			return profile.MachineBinding{}, false, http.StatusOK, nil
		}
	}

	hostname, _ := os.Hostname()
	machineName := strings.TrimSpace(hostname)
	if machineName == "" {
		machineName = "AgentTeam Desktop"
	}
	createEndpoint := strings.TrimRight(target.ServerURL, "/") + machinesPath
	var created serverMachineCreateResponse
	status, err = doServerJSON(
		ctx, client, http.MethodPost, createEndpoint,
		map[string]string{"name": machineName}, accessToken, &created,
	)
	if status == http.StatusUnauthorized {
		accessToken, err = service.auth.RefreshUserToken(ctx, target.AuthID, accessToken)
		if err == nil {
			status, err = doServerJSON(
				ctx, client, http.MethodPost, createEndpoint,
				map[string]string{"name": machineName}, accessToken, &created,
			)
		}
	}
	if err != nil {
		return profile.MachineBinding{}, false, status, err
	}
	created.Machine.ID = strings.TrimSpace(created.Machine.ID)
	created.APIKey = strings.TrimSpace(created.APIKey)
	if created.Machine.ID == "" || created.APIKey == "" {
		return profile.MachineBinding{}, false, http.StatusBadGateway, fmt.Errorf("AgentTeam Server returned an invalid Machine credential")
	}

	binding = profile.MachineBinding{
		ServerURL:   target.ServerURL,
		WorkspaceID: workspaceID,
		MachineID:   created.Machine.ID,
		APIKey:      created.APIKey,
	}
	persisted, err := service.servers.UpsertMachineBinding(binding)
	if err != nil {
		deleteEndpoint := createEndpoint + "/" + url.PathEscape(created.Machine.ID)
		_, _ = doServerJSON(ctx, client, http.MethodDelete, deleteEndpoint, nil, accessToken, nil)
		return profile.MachineBinding{}, false, http.StatusInternalServerError, fmt.Errorf("unable to connect this Desktop to the Workspace")
	}
	if status, err := service.waitForServerConnection(ctx, persisted.ID); err != nil {
		return profile.MachineBinding{}, false, status, err
	}
	return binding, true, http.StatusOK, nil
}

func (service *Service) waitForCurrentMachine(ctx context.Context, target userauth.Target, binding profile.MachineBinding) (int, error) {
	for _, server := range service.bindingServers(target) {
		if strings.TrimSpace(server.MachineID) == strings.TrimSpace(binding.MachineID) {
			return service.waitForServerConnection(ctx, server.ID)
		}
	}
	return http.StatusInternalServerError, fmt.Errorf("the local Desktop machine binding is unavailable")
}

func (service *Service) waitForServerConnection(ctx context.Context, serverID string) (int, error) {
	if service.connectionReadiness == nil {
		return http.StatusOK, nil
	}
	waitCtx, cancel := context.WithTimeout(ctx, desktopMachineConnectionTimeout)
	defer cancel()
	if err := service.connectionReadiness.WaitForServerConnection(waitCtx, serverID); err != nil {
		return http.StatusGatewayTimeout, fmt.Errorf("this Desktop could not connect to the Workspace: %w", err)
	}
	return http.StatusOK, nil
}

func (service *Service) reconcileCurrentBindingLocked(ctx context.Context, target userauth.Target, replaceUnresolved bool) (profile.MachineBinding, bool, int, error) {
	if service == nil || service.auth == nil || service.servers == nil {
		return profile.MachineBinding{}, false, http.StatusServiceUnavailable, fmt.Errorf("Desktop machine setup is unavailable")
	}
	client, ok := service.auth.HTTPClient(target.AuthID)
	if !ok || client == nil {
		return profile.MachineBinding{}, false, http.StatusBadGateway, fmt.Errorf("the active AgentTeam Server is unavailable")
	}

	var current *profile.AgentTeamServer
	for _, server := range service.bindingServers(target) {
		valid, status, err := validateServerBinding(ctx, client, target, server)
		if err != nil {
			return profile.MachineBinding{}, false, status, err
		}
		if !valid {
			if err := service.servers.Delete(server.ID); err != nil {
				return profile.MachineBinding{}, false, http.StatusInternalServerError, fmt.Errorf("unable to remove a stale Desktop machine binding")
			}
			continue
		}
		if current == nil {
			server := server
			current = &server
		}
	}
	if current == nil {
		serverURL := strings.TrimRight(strings.TrimSpace(target.ServerURL), "/")
		workspaceID := strings.TrimSpace(target.WorkspaceID)
		var enabledLegacy []profile.AgentTeamServer
		var disabledLegacy []profile.AgentTeamServer
		for _, server := range service.servers.All() {
			if strings.TrimRight(strings.TrimSpace(server.ServerURL), "/") != serverURL ||
				strings.TrimSpace(server.WorkspaceID) != workspaceID ||
				strings.TrimSpace(server.MachineID) != "" || strings.TrimSpace(server.APIKey) == "" {
				continue
			}
			if server.Enabled {
				enabledLegacy = append(enabledLegacy, server)
			} else {
				disabledLegacy = append(disabledLegacy, server)
			}
		}

		legacyCandidates := append(enabledLegacy, disabledLegacy...)
		for _, server := range legacyCandidates {
			resolved, status, err := resolveServerBinding(ctx, client, target, server)
			if status == http.StatusUnauthorized {
				continue
			}
			if err != nil {
				return profile.MachineBinding{}, false, status, err
			}
			machineID := strings.TrimSpace(resolved.MachineID)
			if machineID == "" || strings.TrimSpace(resolved.WorkspaceID) != workspaceID {
				continue
			}

			enabled := true
			empty := ""
			updated, err := service.servers.Patch(server.ID, profile.ServerUpdate{
				Enabled:          &enabled,
				ServerURL:        &serverURL,
				WorkspaceID:      &workspaceID,
				MachineID:        &machineID,
				AuthToken:        &empty,
				ConnectionStatus: &empty,
			})
			if err != nil {
				return profile.MachineBinding{}, false, http.StatusInternalServerError, fmt.Errorf("unable to restore the legacy Desktop machine binding: %w", err)
			}
			return profile.MachineBinding{
				ServerURL:   updated.ServerURL,
				WorkspaceID: updated.WorkspaceID,
				MachineID:   updated.MachineID,
				APIKey:      updated.APIKey,
			}, true, http.StatusOK, nil
		}
		if len(legacyCandidates) > 0 {
			if replaceUnresolved {
				return profile.MachineBinding{}, false, http.StatusOK, nil
			}
			return profile.MachineBinding{}, false, http.StatusConflict, errLegacyBindingRecoveryRequired
		}
		return profile.MachineBinding{}, false, http.StatusOK, nil
	}

	binding := profile.MachineBinding{
		ServerURL:   current.ServerURL,
		WorkspaceID: current.WorkspaceID,
		MachineID:   current.MachineID,
		APIKey:      current.APIKey,
	}
	if !current.Enabled {
		if _, err := service.servers.UpsertMachineBinding(binding); err != nil {
			return profile.MachineBinding{}, false, http.StatusInternalServerError, fmt.Errorf("unable to reconnect this Desktop to the Workspace")
		}
	}
	return binding, true, http.StatusOK, nil
}

func validateServerBinding(
	ctx context.Context,
	client *http.Client,
	target userauth.Target,
	server profile.AgentTeamServer,
) (bool, int, error) {
	resolved, status, err := resolveServerBinding(ctx, client, target, server)
	if status == http.StatusUnauthorized {
		return false, status, nil
	}
	if err != nil {
		return false, status, err
	}
	valid := strings.TrimSpace(resolved.MachineID) == strings.TrimSpace(server.MachineID) &&
		strings.TrimSpace(resolved.WorkspaceID) == strings.TrimSpace(target.WorkspaceID)
	return valid, status, nil
}

func resolveServerBinding(
	ctx context.Context,
	client *http.Client,
	target userauth.Target,
	server profile.AgentTeamServer,
) (serverMachineAuthResolution, int, error) {
	endpoint := strings.TrimRight(target.ServerURL, "/") + "/api/v1/machine-auth-resolutions"
	var resolved serverMachineAuthResolution
	status, err := doServerJSON(ctx, client, http.MethodPost, endpoint, map[string]string{
		"serverUrl": strings.TrimRight(strings.TrimSpace(server.ServerURL), "/"),
		"apiKey":    strings.TrimSpace(server.APIKey),
	}, "", &resolved)
	return resolved, status, err
}

func doServerJSON(ctx context.Context, client *http.Client, method, endpoint string, requestBody any, accessToken string, responseBody any) (int, error) {
	var body io.Reader = http.NoBody
	if requestBody != nil {
		data, err := json.Marshal(requestBody)
		if err != nil {
			return 0, err
		}
		body = bytes.NewReader(data)
	}
	request, err := http.NewRequestWithContext(ctx, method, endpoint, body)
	if err != nil {
		return 0, err
	}
	request.Header.Set("Accept", "application/json")
	if requestBody != nil {
		request.Header.Set("Content-Type", "application/json")
	}
	if strings.TrimSpace(accessToken) != "" {
		request.Header.Set("Authorization", "Bearer "+accessToken)
	}
	response, err := client.Do(request)
	if err != nil {
		return 0, err
	}
	defer response.Body.Close()
	data, err := io.ReadAll(io.LimitReader(response.Body, maxServerResponseBytes+1))
	if err != nil {
		return response.StatusCode, err
	}
	if len(data) > maxServerResponseBytes {
		return response.StatusCode, fmt.Errorf("AgentTeam Server response is too large")
	}
	if response.StatusCode < 200 || response.StatusCode >= 300 {
		var apiError struct {
			Error string `json:"error"`
		}
		_ = json.Unmarshal(data, &apiError)
		message := strings.TrimSpace(apiError.Error)
		if message == "" {
			message = http.StatusText(response.StatusCode)
		}
		return response.StatusCode, fmt.Errorf("%s", message)
	}
	if responseBody == nil || len(data) == 0 {
		return response.StatusCode, nil
	}
	if err := json.Unmarshal(data, responseBody); err != nil {
		return response.StatusCode, fmt.Errorf("decode AgentTeam Server response: %w", err)
	}
	return response.StatusCode, nil
}

func writeUpstreamError(c *gin.Context, status int, err error) {
	if status < 400 || status > 599 {
		status = http.StatusBadGateway
	}
	response := gin.H{"error": err.Error()}
	if errors.Is(err, errLegacyBindingRecoveryRequired) {
		response["code"] = legacyBindingRecoveryRequiredCode
	}
	c.JSON(status, response)
}
