package mcp

import (
	"context"
	"encoding/json"
	"fmt"
	"log/slog"
	"strings"

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

type reactionAggregate struct {
	Emoji    string `json:"emoji"`
	Count    int    `json:"count"`
	Reactors []struct {
		AuthorProfile types.AuthorProfile `json:"authorProfile"`
	} `json:"reactors,omitempty"`
}

func (h *mcpHandler) toolGetReactions(ctx context.Context, api *apiclient.Client, args json.RawMessage) *types.MCPToolResult {
	var request struct {
		MessageID string `json:"message_id"`
	}
	if err := json.Unmarshal(args, &request); err != nil {
		return toolError("invalid arguments: " + err.Error())
	}
	messageID := strings.TrimSpace(request.MessageID)
	if messageID == "" {
		return toolError("message_id is required")
	}

	var response struct {
		Reactions []reactionAggregate `json:"reactions"`
	}
	if err := api.Post(ctx, api.AgentRuntimePath("/reactions/get"), map[string]any{
		"message_id": messageID,
	}, &response); err != nil {
		return toolError(err.Error())
	}

	return toolText(formatReactionSummary("Current reactions", messageID, response.Reactions))
}

func (h *mcpHandler) toolAddReaction(ctx context.Context, api *apiclient.Client, args json.RawMessage) *types.MCPToolResult {
	return h.toolMutateReaction(ctx, api, args, "add", "/reactions/add")
}

func (h *mcpHandler) toolRemoveReaction(ctx context.Context, api *apiclient.Client, args json.RawMessage) *types.MCPToolResult {
	return h.toolMutateReaction(ctx, api, args, "remove", "/reactions/remove")
}

func (h *mcpHandler) toolSetReaction(ctx context.Context, api *apiclient.Client, args json.RawMessage) *types.MCPToolResult {
	var request struct {
		Op string `json:"op"`
	}
	if err := json.Unmarshal(args, &request); err != nil {
		return toolError("invalid arguments: " + err.Error())
	}
	switch strings.ToLower(strings.TrimSpace(request.Op)) {
	case "add":
		return h.toolMutateReaction(ctx, api, args, "add", "/reactions/add")
	case "remove":
		return h.toolMutateReaction(ctx, api, args, "remove", "/reactions/remove")
	default:
		return toolError(`op must be "add" or "remove"`)
	}
}

func (h *mcpHandler) toolMutateReaction(ctx context.Context, api *apiclient.Client, args json.RawMessage, verb string, pathSuffix string) *types.MCPToolResult {
	var request struct {
		MessageID string `json:"message_id"`
		Emoji     string `json:"emoji"`
	}
	if err := json.Unmarshal(args, &request); err != nil {
		return toolError("invalid arguments: " + err.Error())
	}
	messageID := strings.TrimSpace(request.MessageID)
	if messageID == "" {
		return toolError("message_id is required")
	}
	emoji := strings.TrimSpace(request.Emoji)
	if emoji == "" {
		return toolError("emoji is required")
	}

	agentID := strings.TrimSpace(firstNonEmptyString(api.LocalAgentID, api.AgentID))
	wakeToken := ""
	if verb == "add" && h.c != nil && h.runtime != nil {
		wakeToken = h.runtime.PrepareVisibleReply(agentID, messageID)
	}

	var response struct {
		Changed   bool                `json:"changed"`
		Reactions []reactionAggregate `json:"reactions"`
	}
	if err := api.Post(ctx, api.AgentRuntimePath(pathSuffix), map[string]any{
		"message_id": messageID,
		"emoji":      emoji,
	}, &response); err != nil {
		return toolError(err.Error())
	}

	title := "Reaction added"
	if verb == "remove" {
		title = "Reaction removed"
	}
	if !response.Changed {
		if verb == "add" {
			title = "Reaction already present"
		} else {
			title = "Reaction was not present"
		}
	}
	if verb == "add" && response.Changed {
		h.confirmReactionReply(agentID, wakeToken, messageID)
	}
	return toolText(formatReactionSummary(title, messageID, response.Reactions))
}

func (h *mcpHandler) confirmReactionReply(agentID, wakeToken, messageID string) {
	if h == nil || h.c == nil || h.runtime == nil || strings.TrimSpace(wakeToken) == "" {
		return
	}
	if ok := h.runtime.ConfirmReactionReply(agentID, wakeToken, messageID); !ok {
		slog.Warn("agentteam message_reaction_set wake confirmation was rejected",
			"agent_id", agentID,
			"message_id", messageID,
		)
	}
}

func formatReactionSummary(title string, messageID string, reactions []reactionAggregate) string {
	var sb strings.Builder
	sb.WriteString(strings.TrimSpace(title))
	if trimmed := strings.TrimSpace(messageID); trimmed != "" {
		sb.WriteString(".\n")
		sb.WriteString("messageId: ")
		sb.WriteString(trimmed)
	} else {
		sb.WriteString(".")
	}
	if len(reactions) == 0 {
		sb.WriteString("\nreactions: none")
		return sb.String()
	}

	sb.WriteString("\nreactions:")
	for _, reaction := range reactions {
		emoji := strings.TrimSpace(reaction.Emoji)
		if emoji == "" {
			emoji = "(unknown)"
		}
		sb.WriteString("\n- ")
		sb.WriteString(emoji)
		sb.WriteString(" x")
		sb.WriteString(fmt.Sprintf("%d", reaction.Count))

		if len(reaction.Reactors) > 0 {
			sb.WriteString(" (reactor names omitted; counts-only)")
		}
	}
	return sb.String()
}
