package promptcompiler

import (
	"sort"
	"strings"

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

func RenderThreadContextGuidance(target, readHistoryTool string, compact bool) string {
	data := threadContextTemplateData(target, readHistoryTool)
	if !data.Enabled {
		return ""
	}
	id := "event.thread_context_guidance"
	if compact {
		id = "event.thread_context_compact_guidance"
	}
	return renderRegisteredPromptText(id, newThreadContextPromptInput(data))
}

func threadContextTemplateData(target, readHistoryTool string) ThreadContextTemplateData {
	facts, ok := threadcontext.ClassifyReplyThread(target, readHistoryTool)
	if !ok {
		return ThreadContextTemplateData{}
	}
	return ThreadContextTemplateData{Enabled: true, Target: facts.Target, ReadHistoryTool: facts.ReadHistoryTool}
}

func buildStartUserInput(runtime string, binding ConversationBinding, msg types.InboxMessage) string {
	data := normalizeMessagePromptData(strings.TrimSpace(msg.Target), msg)
	return buildStartUserInputData(runtime, binding, data)
}

func buildStartUserInputData(runtime string, binding ConversationBinding, data MessagePromptData) string {
	value, ok := startUserInputTemplateData(runtime, binding, data)
	if !ok {
		return ""
	}
	return renderRegisteredPromptText("event.current_message", newCurrentMessagePromptInput(value))
}

func startUserInputTemplateData(runtime string, binding ConversationBinding, data MessagePromptData) (CurrentMessageTemplateData, bool) {
	if !messagePromptHasExplicit(data) || data.Author.ActorType == "system" {
		return CurrentMessageTemplateData{}, false
	}
	target := strings.TrimSpace(binding.TargetID)
	if messageTarget := strings.TrimSpace(data.Target); messageTarget != "" {
		target = messageTarget
	} else if target == "" {
		target = strings.TrimSpace(binding.ChannelID)
	}
	discussionReplyTool := toolNamePrefix(runtime, "agentteam")("message_send")
	activeTaskTarget := SelectPromptActiveTaskTarget(binding.ActiveTaskTarget, promptFactsInboxMessage(data))
	activeTaskDirectRouting := ""
	if activeTaskTarget.Valid() {
		activeTaskDirectRouting = FormatActiveTaskDirectMessageRoutingPrompt(target, data.MessageType, toolNamePrefix(runtime, "agentteam")("message_send"), toolNamePrefix(runtime, "agentteam")("message_history_read"))
	}
	activeTaskPrompt := joinPromptSections(formatActiveTaskTargetPrompt(activeTaskTarget, discussionReplyTool), activeTaskDirectRouting)
	return CurrentMessageTemplateData{
		Message:                   formatPromptMessageData(dataWithTarget(data, target), discussionReplyTool),
		ActiveTaskTarget:          joinPromptSections(formatWorkflowContextPrompt(data.WorkflowContext), activeTaskPrompt),
		AgentAuthoredWakeGuidance: formatAgentAuthoredWakeGuidanceData(data),
	}, true
}

func buildWakeOrResumeText(runtime string, binding ConversationBinding, unreadSummary map[string]int, msg types.InboxMessage, memoryResumeReminder string) string {
	data := normalizeMessagePromptData(strings.TrimSpace(msg.Target), msg)
	return buildWakeOrResumeTextData(runtime, binding, unreadSummary, data, memoryResumeReminder)
}

func buildWakeOrResumeTextData(runtime string, binding ConversationBinding, unreadSummary map[string]int, data MessagePromptData, memoryResumeReminder string) string {
	sendMessageTool := toolNamePrefix(runtime, "agentteam")("message_send")
	discussionReplyTool := toolNamePrefix(runtime, "agentteam")("message_send")
	hasMsg := messagePromptHasExplicit(data) && data.Author.ActorType != "system"

	if hasMsg {
		return renderRegisteredPromptText("event.wake_context", newWakeContextPromptInput(wakeContextTemplateData(runtime, binding, data, sendMessageTool, discussionReplyTool, memoryResumeReminder)))
	}
	if len(unreadSummary) > 0 {
		return buildUnreadPrompt(unreadSummary)
	}
	return renderRegisteredPromptText("event.resume_context", newResumeContextPromptInput(ResumeContextTemplateData{SendMessageTool: sendMessageTool}))
}

func buildWakePrompt(runtime string, binding ConversationBinding, msg types.InboxMessage, sendMessageTool, discussionReplyTool string) string {
	data := normalizeMessagePromptData(strings.TrimSpace(msg.Target), msg)
	return buildWakePromptData(runtime, binding, data, sendMessageTool, discussionReplyTool)
}

func buildWakePromptData(runtime string, binding ConversationBinding, data MessagePromptData, sendMessageTool, discussionReplyTool string) string {
	templateData := wakeContextTemplateData(runtime, binding, data, sendMessageTool, discussionReplyTool, "")
	return renderRegisteredPromptText("event.wake_context", newWakeContextPromptInput(templateData))
}

func wakeContextTemplateData(runtime string, binding ConversationBinding, data MessagePromptData, sendMessageTool, discussionReplyTool, memoryResumeReminder string) WakeContextTemplateData {
	target := strings.TrimSpace(binding.TargetID)
	if messageTarget := strings.TrimSpace(data.Target); messageTarget != "" {
		target = messageTarget
	} else if target == "" {
		target = strings.TrimSpace(binding.ChannelID)
	}
	activeTaskTarget := SelectPromptActiveTaskTarget(binding.ActiveTaskTarget, promptFactsInboxMessage(data))
	activeTaskDirectRouting := ""
	if activeTaskTarget.Valid() {
		activeTaskDirectRouting = FormatActiveTaskDirectMessageRoutingPrompt(target, data.MessageType, sendMessageTool, toolNamePrefix(runtime, "agentteam")("message_history_read"))
	}
	activeTaskPrompt := joinPromptSections(formatActiveTaskTargetPrompt(activeTaskTarget, sendMessageTool), activeTaskDirectRouting)
	return WakeContextTemplateData{
		Message:                   formatPromptMessageData(dataWithTarget(data, target), discussionReplyTool),
		ThreadContext:             threadContextTemplateData(target, toolNamePrefix(runtime, "agentteam")("message_history_read")),
		ActiveTaskTarget:          joinPromptSections(formatWorkflowContextPrompt(data.WorkflowContext), activeTaskPrompt),
		AgentAuthoredWakeGuidance: formatAgentAuthoredWakeGuidanceData(data), SendMessageTool: sendMessageTool,
		MemoryResumeReminder: memoryResumeReminder,
	}
}

func buildUnreadPrompt(unreadSummary map[string]int) string {
	templateData := unreadSummaryTemplateData(unreadSummary)
	return renderRegisteredPromptText("event.unread_summary", newUnreadSummaryPromptInput(templateData))
}

func unreadSummaryTemplateData(unreadSummary map[string]int) UnreadSummaryTemplateData {
	channels := make([]UnreadSummaryChannel, 0, len(unreadSummary))
	for channel, count := range unreadSummary {
		channel = strings.TrimSpace(channel)
		if channel == "" || count <= 0 {
			continue
		}
		channels = append(channels, UnreadSummaryChannel{Channel: channel, Count: count})
	}
	sort.Slice(channels, func(i, j int) bool { return channels[i].Channel < channels[j].Channel })
	return UnreadSummaryTemplateData{Channels: channels}
}

func buildDeferredContinuationPrompt(msg types.InboxMessage, remaining int, replyToolName, discussionReplyTool, memoryResumeReminder string) string {
	data := normalizeMessagePromptData(strings.TrimSpace(msg.Target), msg)
	return buildDeferredContinuationPromptData(data, remaining, replyToolName, discussionReplyTool, memoryResumeReminder)
}

func buildDeferredContinuationPromptData(data MessagePromptData, remaining int, replyToolName, discussionReplyTool, memoryResumeReminder string) string {
	target := strings.TrimSpace(data.Target)
	if target == "" {
		target = inferredTarget(promptFactsInboxMessage(data))
	}
	authorityMessage := promptFactsInboxMessage(data)
	authorityMessage.Target = target
	return renderRegisteredPromptText("event.deferred_continuation", newDeferredContinuationPromptInput(deferredContinuationTemplateData(data, remaining, replyToolName, discussionReplyTool, memoryResumeReminder)))
}

func deferredContinuationTemplateData(data MessagePromptData, remaining int, replyToolName, discussionReplyTool, memoryResumeReminder string) DeferredContinuationTemplateData {
	target := strings.TrimSpace(data.Target)
	if target == "" {
		target = inferredTarget(promptFactsInboxMessage(data))
	}
	authorityMessage := promptFactsInboxMessage(data)
	authorityMessage.Target = target
	return DeferredContinuationTemplateData{
		Message: formatPromptMessageData(dataWithTarget(data, target), discussionReplyTool), WorkflowContext: formatWorkflowContextPrompt(data.WorkflowContext), Remaining: remaining,
		AgentAuthoredWakeGuidance: formatAgentAuthoredWakeGuidanceData(data), ReplyToolName: replyToolName,
		ReplyAuthority: types.MessageHasReplyAuthority(authorityMessage), Reaction: data.MessageType == "reaction",
		TaskScopeDiscussion: data.MessageType == "task_discussion", TaskDiscussionDispatch: data.HasTask && data.Task.Discussion != nil, MemoryResumeReminder: memoryResumeReminder,
	}
}

func formatAgentAuthoredWakeGuidanceData(data MessagePromptData) string {
	if data.Author.ActorType != "agent" || data.MessageType == "reaction" {
		return ""
	}
	return renderRegisteredPromptText("event.agent_authored_wake_guidance", newEmptyPromptInput(PromptInputMessage))
}

func dataWithTarget(data MessagePromptData, target string) MessagePromptData {
	data.Target = strings.TrimSpace(target)
	return data
}

func promptFactsInboxMessage(data MessagePromptData) types.InboxMessage {
	return types.InboxMessage{
		MessageID: data.MessageID, Target: data.Target, TargetSeq: data.TargetSeq,
		ChannelType: data.ChannelType, ChannelName: data.ChannelName, Content: data.Content, Timestamp: data.Timestamp,
		MessageType: data.MessageType, AuthorProfile: types.AuthorProfile{ActorType: data.Author.ActorType, PrincipalID: data.Author.PrincipalID, MemberID: data.Author.MemberID, TargetID: data.Author.TargetID, DisplayName: data.Author.DisplayName},
		ActiveTaskTarget: data.ActiveTaskTarget,
	}
}

func inferredTarget(msg types.InboxMessage) string {
	if strings.TrimSpace(msg.Target) != "" {
		return strings.TrimSpace(msg.Target)
	}
	switch strings.TrimSpace(msg.ChannelType) {
	case "dm":
		return "dm:@" + strings.TrimSpace(msg.ChannelName)
	case "thread":
		return strings.TrimSpace(msg.ChannelName)
	case "workflow":
		return "workflow:" + strings.TrimSpace(msg.ChannelName)
	default:
		return "#" + strings.TrimSpace(msg.ChannelName)
	}
}
