package promptcompiler

import (
	"strings"

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

// FormatPromptMessage renders one inbound message with shared AgentTeam prompt details.
func FormatPromptMessage(target string, msg types.InboxMessage, discussionReplyTool string) string {
	formattedTarget := strings.TrimSpace(target)
	return formatPromptMessage(formattedTarget, msg, discussionReplyTool)
}

func promptAuthorMentionName(author types.AuthorIdentity) string {
	if author.ActorType == "agent" {
		return strings.TrimSpace(firstNonEmptyPromptAuthorValue(author.TargetID, author.PrincipalID, author.MemberID, author.DisplayName))
	}
	return strings.TrimSpace(author.DisplayName)
}

func promptAuthorDisplayName(author types.AuthorIdentity) string {
	if author.ActorType != "agent" {
		return ""
	}
	displayName := strings.TrimSpace(author.DisplayName)
	if displayName == "" || displayName == promptAuthorMentionName(author) {
		return ""
	}
	return displayName
}

func promptDeliveryAuthorMentionName(author types.AuthorIdentity) string {
	if author.ActorType != "agent" {
		return ""
	}
	mentionName := promptAuthorMentionName(author)
	if mentionName == "" || mentionName == strings.TrimSpace(author.DisplayName) {
		return ""
	}
	return mentionName
}

func formatPromptAuthorMention(author types.AuthorIdentity) string {
	name := promptAuthorMentionName(author)
	if name != "" && !strings.HasPrefix(name, "@") {
		name = "@" + name
	}
	return name
}

func firstNonEmptyPromptAuthorValue(values ...string) string {
	for _, value := range values {
		if trimmed := strings.TrimSpace(value); trimmed != "" {
			return trimmed
		}
	}
	return ""
}

func formatPromptMessage(target string, msg types.InboxMessage, discussionReplyTool string) string {
	data := normalizeMessagePromptData(target, msg)
	return formatPromptMessageData(data, discussionReplyTool)
}

func formatPromptMessageData(data MessagePromptData, discussionReplyTool string) string {
	return renderRegisteredPromptText("event.message_header", newMessagePromptInput(MessageTemplateData{
		Target: strings.TrimSpace(data.Target), MessageID: strings.TrimSpace(data.MessageID), Timestamp: formatStartTimestamp(data.Timestamp), AgentType: data.Author.ActorType == "agent",
		Author: formatPromptAuthorMention(data.Author), Content: data.Content, DisplayName: promptAuthorDisplayName(data.Author), Details: formatPromptMessageDetailsData(data, discussionReplyTool),
	}))
}

func formatPromptMessageDetailsData(data MessagePromptData, discussionReplyTool string) string {
	sections := MessageDetailsTemplateData{}
	if data.ThreadRoot != nil {
		sections.ThreadRoot = formatReplyThreadRootPromptBlock(*data.ThreadRoot, data.TargetSeq)
	}
	sections.Attachments = formatAttachmentDetails(false, messagePromptAttachments(data.Attachments))
	if teamContexts := formatWorkflowTeamContextPromptDetails(data.TeamContexts); teamContexts != "" {
		sections.TeamContexts = teamContexts
	} else {
		sections.TeamContexts = formatTeamContextPromptDetails(data.TeamContexts)
	}
	if data.HasTask {
		sections.Task = formatTaskDispatchPromptMetadata(data.Task, discussionReplyTool)
	}
	if data.WorkflowEdit != nil {
		sections.WorkflowEdit = formatWorkflowAgentEditPrompt(*data.WorkflowEdit)
	}
	if data.MessageType == "task_discussion" && data.Target != "" {
		sections.TaskScope = formatTaskScopeDiscussionPromptDetails(data.Target, types.InboxMessage{MessageType: data.MessageType, Target: data.Target}, discussionReplyTool)
	}
	if data.Reaction != nil {
		sections.Reaction = formatReactionPromptData(*data.Reaction)
	}
	if sections.ThreadRoot == "" && sections.Attachments == "" && sections.TeamContexts == "" && sections.Task == "" && sections.WorkflowEdit == "" && sections.TaskScope == "" && sections.Reaction == "" {
		return ""
	}
	return renderRegisteredPromptText("event.message_details", newMessageDetailsPromptInput(sections))
}

func formatReplyThreadRootPromptDetails(msg types.InboxMessage) string {
	root, ok := msg.ReplyThreadRoot()
	if !ok {
		return ""
	}
	return formatReplyThreadRootPromptBlock(root, msg.TargetSeq)
}

func formatAttachmentDetails(threadRoot bool, attachments []types.MessageAttachment) string {
	if len(attachments) == 0 {
		return ""
	}
	items := make([]MessageAttachmentDetailItem, 0, len(attachments))
	for _, attachment := range attachments {
		items = append(items, MessageAttachmentDetailItem{ID: strings.TrimSpace(attachment.ID), Filename: strings.TrimSpace(attachment.Filename), ContentType: strings.TrimSpace(attachment.ContentType), SizeBytes: attachment.SizeBytes})
	}
	return renderRegisteredPromptText("event.attachment_details", newAttachmentDetailsPromptInput(AttachmentDetailsTemplateData{ThreadRoot: threadRoot, Attachments: items}))
}

func formatReplyThreadRootPromptBlock(root types.ReplyThreadRoot, targetSeq int64) string {
	messageID := strings.TrimSpace(root.MessageID)
	if len(messageID) > 8 {
		messageID = messageID[:8]
	}
	authorIdentity := root.AuthorIdentity()
	return renderRegisteredPromptText("event.thread_root", newThreadRootPromptInput(ThreadRootTemplateData{
		MessageID: messageID, Timestamp: formatStartTimestamp(root.Timestamp), MessageType: strings.TrimSpace(root.MessageType),
		Author: formatPromptAuthorMention(authorIdentity), Content: strings.TrimSpace(root.Content), DisplayName: promptAuthorDisplayName(authorIdentity),
		AttachmentDetails: formatAttachmentDetails(true, root.Attachments), EarlierReplyCount: max(targetSeq-1, 0),
	}))
}

func formatReactionPromptData(reaction ReactionPromptData) string {
	input := newReactionPromptInput(reaction)
	return renderRegisteredPromptText("event.reaction_details", input)
}

func formatStartTimestamp(ts string) string {
	ts = strings.TrimSpace(ts)
	if ts == "" {
		return "-"
	}
	return ts
}
