package exec

import (
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/require"

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

type paginationChannelRuntime struct {
	channelRuntime
	listInput    channelListInput
	membersInput channelMembersInput
	listResult   channelListOutput
	memberResult channelMembersOutput
}

func (runtime *paginationChannelRuntime) list(_ context.Context, input channelListInput) (channelListOutput, error) {
	runtime.listInput = input
	return runtime.listResult, nil
}

func (runtime *paginationChannelRuntime) members(_ context.Context, input channelMembersInput) (channelMembersOutput, error) {
	runtime.membersInput = input
	return runtime.memberResult, nil
}

func TestChannelHandlersPassPaginationInputsAndOutputs(t *testing.T) {
	runtime := &paginationChannelRuntime{
		listResult: channelListOutput{
			Channels:   []channelListItem{{ChannelID: "chn_1"}},
			HasMore:    true,
			NextCursor: "20",
			TotalCount: 21,
		},
		memberResult: channelMembersOutput{
			ChannelID:  "chn_1",
			Members:    []channelMember{{MemberID: "mem_1", Kind: "human"}},
			HasMore:    true,
			NextCursor: "10",
			TotalCount: 11,
		},
	}
	handler := channelHandler{remote: runtime}

	listed, err := handler.list(context.Background(), actionScopedJSON[channelListInput]{
		Body: channelListInput{Limit: 20, Cursor: "5"},
	})
	require.NoError(t, err)
	require.Equal(t, channelListInput{Limit: 20, Cursor: "5"}, runtime.listInput)
	require.True(t, listed.Data.HasMore)
	require.Equal(t, "20", listed.Data.NextCursor)
	require.Equal(t, 21, listed.Data.TotalCount)

	members, err := handler.members(context.Background(), actionScopedJSON[channelMembersInput]{
		Body: channelMembersInput{ChannelID: " chn_1 ", Limit: 10, Cursor: "2"},
	})
	require.NoError(t, err)
	require.Equal(t, channelMembersInput{ChannelID: "chn_1", Limit: 10, Cursor: "2"}, runtime.membersInput)
	require.True(t, members.Data.HasMore)
	require.Equal(t, "10", members.Data.NextCursor)
	require.Equal(t, 11, members.Data.TotalCount)
}

func TestChannelRemoteSendsPaginationContinuation(t *testing.T) {
	var requests []string
	var membersBody channelMembersInput
	server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		requests = append(requests, request.Method+" "+request.URL.RequestURI())
		switch request.URL.Path {
		case "/api/v1/workspaces/ws/agents/agent/runtime/channels":
			_, _ = io.WriteString(writer, `{"channels":[],"hasMore":true,"nextCursor":"7","totalCount":8}`)
		case "/api/v1/workspaces/ws/agents/agent/runtime/channels/members":
			require.NoError(t, json.NewDecoder(request.Body).Decode(&membersBody))
			_, _ = io.WriteString(writer, `{"channelId":"chn_1","members":[],"hasMore":true,"nextCursor":"9","totalCount":10}`)
		default:
			http.NotFound(writer, request)
		}
	}))
	defer server.Close()

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

	list, err := remote.list(context.Background(), channelListInput{Limit: 7, Cursor: "3"})
	require.NoError(t, err)
	require.True(t, list.HasMore)
	require.Equal(t, "7", list.NextCursor)

	members, err := remote.members(context.Background(), channelMembersInput{ChannelID: "chn_1", Limit: 9, Cursor: "4"})
	require.NoError(t, err)
	require.True(t, members.HasMore)
	require.Equal(t, "9", members.NextCursor)

	require.Equal(t, []string{
		"GET /api/v1/workspaces/ws/agents/agent/runtime/channels?cursor=3&limit=7",
		"POST /api/v1/workspaces/ws/agents/agent/runtime/channels/members",
	}, requests)
	require.Equal(t, channelMembersInput{ChannelID: "chn_1", Limit: 9, Cursor: "4"}, membersBody)
}
