package exec

import (
	"context"
	"io"
	"net/http"
	"net/http/httptest"
	"sync"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/wire/apiclient"
)

func TestChannelRemoteRetriesLostMutationResponsesWithIdenticalReceiptBody(t *testing.T) {
	var (
		mu     sync.Mutex
		bodies = make(map[string][][]byte)
	)
	server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		body, err := io.ReadAll(request.Body)
		require.NoError(t, err)
		path := request.URL.Path
		mu.Lock()
		bodies[path] = append(bodies[path], append([]byte(nil), body...))
		attempt := len(bodies[path])
		mu.Unlock()

		if attempt == 1 {
			hijacker, ok := writer.(http.Hijacker)
			require.True(t, ok)
			connection, _, err := hijacker.Hijack()
			require.NoError(t, err)
			require.NoError(t, connection.Close())
			return
		}

		switch {
		case path == "/api/v1/workspaces/ws/agents/agent/runtime/channels/create":
			_, _ = io.WriteString(writer, `{"channel":{"channelId":"chn_1","slug":"one","displayName":"One","description":"","visibility":"private","version":1}}`)
		case path == "/api/v1/workspaces/ws/agents/agent/runtime/channels/update":
			_, _ = io.WriteString(writer, `{"channel":{"channelId":"chn_1","slug":"one","displayName":"Renamed","description":"","visibility":"private","version":2}}`)
		default:
			_, _ = io.WriteString(writer, `{"channelId":"chn_1","agents":[{"memberId":"agt_1","displayName":"Agent One"}]}`)
		}
	}))
	defer server.Close()

	retries := 0
	remote := channelRemote{client: &apiclient.Client{
		ServerURL: server.URL, AgentID: "agent", AuthToken: "token", RouteWorkspaceID: "ws",
		HTTPClient: server.Client(), RecordAPIRetry: func() { retries++ },
	}}

	created, err := remote.create(context.Background(), channelCreateRequest{
		RequestID: "req-create", DisplayName: "One",
	})
	require.NoError(t, err)
	require.Equal(t, "chn_1", created.Channel.ChannelID)

	displayName := "Renamed"
	updated, err := remote.update(context.Background(), "chn_1", channelUpdateRequest{
		RequestID: "req-update", ChannelID: "chn_1", ExpectedVersion: 1, DisplayName: &displayName,
	})
	require.NoError(t, err)
	require.Equal(t, int64(2), updated.Channel.Version)

	added, err := remote.agentAdd(context.Background(), "chn_1", channelAgentMutationRequest{
		RequestID: "req-add", ChannelID: "chn_1",
		Agents: []channelAgentReference{{AgentID: "agt_1"}},
	})
	require.NoError(t, err)
	require.Equal(t, channelAgentMember{MemberID: "agt_1", DisplayName: "Agent One"}, added.Agents[0])

	removed, err := remote.agentRemove(context.Background(), "chn_1", channelAgentMutationRequest{
		RequestID: "req-remove", ChannelID: "chn_1",
		Agents: []channelAgentReference{{AgentID: "agt_1"}},
	})
	require.NoError(t, err)
	require.Equal(t, added, removed)

	require.Equal(t, 4, retries)
	mu.Lock()
	defer mu.Unlock()
	require.Len(t, bodies, 4)
	for path, attempts := range bodies {
		require.Len(t, attempts, 2, path)
		require.Equal(t, attempts[0], attempts[1], path+" must replay identical JSON bytes")
	}
}
