package api

import (
	"context"
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/AgentTeam/desktop/internal/api/mcp"
	"github.com/tidbcloud/AgentTeam/desktop/internal/memorysearch"
	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
	"github.com/tidbcloud/AgentTeam/desktop/internal/wire/apiclient"
)

type agentteamMCPTestHandler struct{ defs []types.MCPToolDef }

func (h agentteamMCPTestHandler) Tools() []types.MCPToolDef { return h.defs }
func (h agentteamMCPTestHandler) CallTool(_ context.Context, _ string, name string, _ json.RawMessage) *types.MCPToolResult {
	return &types.MCPToolResult{Content: []types.MCPToolContent{{Type: "text", Text: "called " + name}}}
}
func (h agentteamMCPTestHandler) SkillDoc(types.ToolNamer) string { return "" }
func (h agentteamMCPTestHandler) SkillDocSplit(types.ToolNamer) types.SkillDocParts {
	return types.SkillDocParts{}
}
func (h agentteamMCPTestHandler) AcknowledgeMCPToolResultDelivery(string, string, []string, types.MCPToolDeliveryOutcome) {
}

type agentteamMCPTestMemory struct{}

func (agentteamMCPTestMemory) MemorySearchAvailable(context.Context, string) bool { return false }
func (agentteamMCPTestMemory) MemorySearch(context.Context, string, memorysearch.SearchRequest) (memorysearch.SearchResponse, error) {
	return memorysearch.SearchResponse{}, nil
}

func TestAgentTeamMCPHandlerToolListingIncludesOnlyAgentTeamNamespaceTools(t *testing.T) {
	message := agentteamMCPTestHandler{defs: []types.MCPToolDef{{Name: "message_send"}}}
	h, err := newAgentTeamMCPHandler(message, agentteamMCPTestMemory{})
	require.NoError(t, err)

	names := map[string]bool{}
	for _, def := range h.Tools() {
		names[def.Name] = true
	}
	require.True(t, names["message_send"])
	require.True(t, names["memory_search"])
	require.False(t, names["task_create"], "tools from an omitted child must not be exposed")

	result := h.CallTool(context.Background(), "agent-1", "task_create", json.RawMessage(`{}`))
	require.True(t, result.IsError)
	require.Contains(t, result.Content[0].Text, "unknown tool: task_create")
}

func TestDynamicAgentTeamRouteRejectsPartiallyConfiguredHandler(t *testing.T) {
	_, ok := newAgentTeamMCPHandlerForRoute(
		mcp.NewMessageService(),
		agentteamMCPTestConnections{},
		nil,
		nil,
		"agentteam-main",
	)
	require.False(t, ok)
}

type agentteamMCPTestConnections struct{}

type agentteamMCPTestMessageRuntime struct{}

func (agentteamMCPTestMessageRuntime) Session(string) (types.SessionSnapshot, bool) {
	return types.SessionSnapshot{}, true
}
func (agentteamMCPTestMessageRuntime) PrepareVisibleReply(string, ...string) string     { return "" }
func (agentteamMCPTestMessageRuntime) ConfirmReactionReply(string, string, string) bool { return true }
func (agentteamMCPTestMessageRuntime) ReconcileInboxMessages(string, []string) error    { return nil }
func (agentteamMCPTestMessageRuntime) ReconcileRuntimeAckedDeliveries(string, []string) ([]string, error) {
	return nil, nil
}
func (agentteamMCPTestMessageRuntime) ReconcileDeferredDeliveriesForAgent(string, []string) ([]string, error) {
	return nil, nil
}
func (agentteamMCPTestMessageRuntime) PrepareRuntimeMessageToolDeliveries(string, []types.InboxMessage) int {
	return 0
}
func (agentteamMCPTestMessageRuntime) AcknowledgeRuntimeMessageToolDeliveriesForSession(string, []string, types.MCPToolDeliveryOutcome, string) {
}
func (agentteamMCPTestMessageRuntime) InboxMessagesForFreshnessPage(string, string, int64, int) (types.InboxReadPage, error) {
	return types.InboxReadPage{}, nil
}
func (agentteamMCPTestMessageRuntime) InboxMessagesForFreshnessPageForRuntime(string, string, int64, int, string) (types.InboxReadPage, error) {
	return types.InboxReadPage{}, nil
}
func (agentteamMCPTestMessageRuntime) PendingRuntimeInputCoversFreshness(string, string, int64) bool {
	return false
}
func (agentteamMCPTestMessageRuntime) MessageFreshnessSnapshot(string, string) (types.MessageFreshnessFrontier, bool) {
	return types.MessageFreshnessFrontier{}, false
}
func (agentteamMCPTestMessageRuntime) RememberMessageFreshnessObserved(string, []types.InboxMessage) bool {
	return false
}
func (agentteamMCPTestMessageRuntime) RememberMessageFreshnessHeld(string, string, int64, int64) bool {
	return false
}
func (agentteamMCPTestMessageRuntime) SetActiveTaskTarget(string, types.ActiveTaskTarget) bool {
	return false
}
func (agentteamMCPTestMessageRuntime) CurrentTurnMessageID(string) string { return "msg-1" }

func (c agentteamMCPTestConnections) ServerConnection(id string) (types.ServerConnection, bool) {
	if id != "agentteam-main" {
		return nil, false
	}
	return agentteamMCPTestConnection{}, true
}
func (c agentteamMCPTestConnections) ServerConnections() []types.ServerConnection { return nil }
func (c agentteamMCPTestConnections) Enable(string) error                         { return nil }
func (c agentteamMCPTestConnections) Disable(string) error                        { return nil }

type agentteamMCPTestConnection struct{}

func (c agentteamMCPTestConnection) ID() string                  { return "agentteam-main" }
func (c agentteamMCPTestConnection) Enabled() bool               { return true }
func (c agentteamMCPTestConnection) Start(context.Context) error { return nil }
func (c agentteamMCPTestConnection) Stop(context.Context) error  { return nil }
func (c agentteamMCPTestConnection) Send(context.Context, types.Metadata, types.OutboundMessage) error {
	return nil
}
func (c agentteamMCPTestConnection) APIClient(...string) *apiclient.Client {
	return &apiclient.Client{}
}
