package message

import (
	"sort"
	"strings"
	"time"
)

const (
	MessageDeliveryRoutingModeSilent                      = "silent"
	MessageDeliveryRoutingModeDirectMentions              = "direct_mentions"
	MessageDeliveryRoutingModeBroadcastAll                = "channel_broadcast_all"
	MessageDeliveryRoutingModeBroadcastOnline             = "channel_broadcast_online"
	MessageDeliveryRoutingModeThreadReply                 = "thread_reply"
	MessageDeliveryRoutingModeDM                          = "dm"
	MessageDeliveryRoutingModeTaskCommandNotify           = "task_command_notify"
	MessageDeliveryRoutingModeOwnerQuote                  = "owner_quote"
	MessageDeliveryRoutingModeOwnerPrivateContext         = "owner_private_context"
	MessageDeliveryContextScopeChannelMainline            = "channel_mainline"
	MessageDeliveryContextScopeThread                     = "thread"
	MessageDeliveryContextScopeDM                         = "dm"
	MessageDeliveryWakeInferenceCurrentRuntime            = "current_runtime_state"
	MessageDeliveryWakeInferenceOutboxState               = "outbox_state"
	MessageDeliveryScopeStatusCurrentScope                = "current_scope"
	MessageDeliveryScopeStatusPreviousScopeMember         = "previous_scope_member"
	MessageDeliveryStatusTargeted                         = "targeted"
	MessageDeliveryStatusExcluded                         = "excluded"
	MessageDeliveryExclusionNoAgentScope                  = "no_agent_delivery_scope"
	MessageDeliveryExclusionNotDirectlyMentioned          = "not_directly_mentioned"
	MessageDeliveryExclusionNotOnlineActive               = "not_online_active_for_broadcast"
	MessageDeliveryExclusionNotInOnlineSnapshot           = MessageDeliveryExclusionNotOnlineActive
	MessageDeliveryExclusionNotThreadParticipant          = "not_thread_participant_or_mentioned"
	MessageDeliveryExclusionNotTaskNotifyTarget           = "not_in_task_notify_targets"
	MessageDeliveryExclusionNotDMPeer                     = "not_dm_peer"
	MessageDeliveryExclusionAuthorExcluded                = "author_excluded"
	MessageDeliveryExclusionNoCurrentScopeMembership      = "no_current_scope_membership"
	MessageDeliveryExclusionNotAuthorOwnedBroadcastAgent  = "not_author_owned_broadcast_agent"
	MessageDeliveryWakeWouldDeliverRunningAgent           = "would_deliver_running_agent"
	MessageDeliveryWakeWouldStartAgent                    = "would_start_agent"
	MessageDeliveryWakeSkippedNotTargeted                 = "skipped_not_targeted"
	MessageDeliveryWakeSkippedAutoWakeDisabled            = "skipped_auto_wake_disabled"
	MessageDeliveryWakeSkippedNoWakeSubscription          = "skipped_no_wake_subscription"
	MessageDeliveryWakeSkippedMachineOffline              = "skipped_machine_offline"
	MessageDeliveryOwnerPrivateStateDeliveredByOwnerQuote = "delivered_by_owner_quote"
	MessageDeliveryOwnerPrivateStateOwnerQuoteRequired    = "owner_quote_required"
)

type MessageDeliveryDiagnostics struct {
	Message                  MessageDeliveryDiagnosticsMessage
	WakeInferenceBasis       string
	WakeInferenceExplanation string
	Summary                  MessageDeliveryDiagnosticsSummary
	Agents                   []MessageDeliveryDiagnosticsAgent
}

type MessageDeliveryDiagnosticsSummary struct {
	TargetedAgentCount      int
	ExcludedAgentCount      int
	WakeDeliverRunningCount int
	WakeStartCount          int
	WakeBlockedCount        int
	OwnerPrivateRequired    bool
}

type MessageDeliveryDiagnosticsMessage struct {
	ID                      string
	ChannelID               string
	ChannelType             string
	ParentChannelID         string
	ParentChannelType       string
	AuthorMemberID          string
	AuthorUserID            string
	AuthorType              string
	MessageType             string
	Content                 string
	CreatedAt               time.Time
	RoutingMode             string
	RoutingExplanation      string
	ContextScope            string
	ContextScopeExplanation string
}

type MessageDeliveryDiagnosticsAgent struct {
	AgentID                 string
	AgentName               string
	MemberID                string
	MachineID               string
	MachineName             string
	AgentStatus             string
	AgentActivity           string
	AgentActivityDetail     string
	AutoWakeEnabled         bool
	SubscriptionState       string
	MachineOnline           bool
	ScopeStatus             string
	ScopeExplanation        string
	DeliveryStatus          string
	DeliveryReason          string
	DeliveryExplanation     string
	ExecutionResult         string
	OwnerPrivateState       string
	OwnerPrivateExplanation string
	WakeStatus              string
	WakeExplanation         string
}

type DiagnosticsAgentState struct {
	AgentID           string
	AgentName         string
	MemberID          string
	MachineID         string
	MachineName       string
	OwnerUserID       string
	AgentStatus       string
	AgentActivity     string
	ActivityDetail    string
	AutoWakeEnabled   bool
	SubscriptionState string
	MachineOnline     bool
	DeliveryReason    string
	ExecutionResult   string
}

func DetectMessageDeliveryRoutingMode(message MessageDeliveryDiagnosticsMessage, routedRecipients []DiagnosticsAgentState) string {
	if ClassifyMessageSemantics(message.MessageType, nil).RenderKind == MessageRenderOwnerQuote {
		return MessageDeliveryRoutingModeOwnerQuote
	}
	for _, recipient := range routedRecipients {
		if recipient.DeliveryReason == AgentDeliveryReasonTaskCommandNotify {
			return MessageDeliveryRoutingModeTaskCommandNotify
		}
	}

	switch message.ChannelType {
	case "dm":
		return MessageDeliveryRoutingModeDM
	case "thread":
		if len(ParseDirectMentionTokens(message.Content)) > 0 {
			hasThreadParticipantRecipient := false
			for _, recipient := range routedRecipients {
				if recipient.DeliveryReason == AgentDeliveryReasonThreadParticipant {
					hasThreadParticipantRecipient = true
					break
				}
			}
			if !hasThreadParticipantRecipient {
				return MessageDeliveryRoutingModeDirectMentions
			}
		}
		return MessageDeliveryRoutingModeThreadReply
	}

	if messageSupportsControlledBroadcast(message) {
		broadcastMode, err := ParseControlledBroadcastMode(message.Content)
		if err == nil {
			switch broadcastMode {
			case ChannelBroadcastModeAll:
				return MessageDeliveryRoutingModeBroadcastAll
			case ChannelBroadcastModeOnline:
				return MessageDeliveryRoutingModeBroadcastOnline
			}
		}
	}

	if len(ParseDirectMentionTokens(message.Content)) > 0 {
		return MessageDeliveryRoutingModeDirectMentions
	}
	for _, recipient := range routedRecipients {
		if recipient.DeliveryReason == AgentDeliveryReasonOwnerPrivateContext {
			return MessageDeliveryRoutingModeOwnerPrivateContext
		}
	}

	return MessageDeliveryRoutingModeSilent
}

func DetectMessageDeliveryContextScope(message MessageDeliveryDiagnosticsMessage) string {
	switch message.ChannelType {
	case "thread":
		return MessageDeliveryContextScopeThread
	case "dm":
		return MessageDeliveryContextScopeDM
	default:
		return MessageDeliveryContextScopeChannelMainline
	}
}

func messageSupportsControlledBroadcast(message MessageDeliveryDiagnosticsMessage) bool {
	if strings.TrimSpace(message.ChannelType) != "channel" {
		return false
	}
	switch strings.TrimSpace(message.AuthorType) {
	case "human", "user":
		return true
	default:
		return false
	}
}

func MergeMessageDeliveryDiagnosticsAgents(currentScopeAgents []DiagnosticsAgentState, routedRecipients []DiagnosticsAgentState) []DiagnosticsAgentState {
	merged := make(map[string]DiagnosticsAgentState, len(currentScopeAgents)+len(routedRecipients))
	for _, agent := range currentScopeAgents {
		merged[agent.AgentID] = agent
	}
	for _, agent := range routedRecipients {
		existing, ok := merged[agent.AgentID]
		if !ok {
			merged[agent.AgentID] = agent
			continue
		}
		if shouldOverrideDiagnosticsDeliveryReason(existing.DeliveryReason, agent.DeliveryReason) {
			existing.DeliveryReason = agent.DeliveryReason
		}
		if strings.TrimSpace(agent.ExecutionResult) != "" {
			existing.ExecutionResult = agent.ExecutionResult
		}
		if strings.TrimSpace(existing.AgentName) == "" {
			existing.AgentName = agent.AgentName
		}
		if strings.TrimSpace(existing.MemberID) == "" {
			existing.MemberID = agent.MemberID
		}
		if strings.TrimSpace(existing.MachineID) == "" {
			existing.MachineID = agent.MachineID
		}
		if strings.TrimSpace(existing.MachineName) == "" {
			existing.MachineName = agent.MachineName
		}
		if strings.TrimSpace(existing.AgentStatus) == "" {
			existing.AgentStatus = agent.AgentStatus
		}
		if strings.TrimSpace(existing.AgentActivity) == "" {
			existing.AgentActivity = agent.AgentActivity
		}
		if strings.TrimSpace(existing.ActivityDetail) == "" {
			existing.ActivityDetail = agent.ActivityDetail
		}
		if strings.TrimSpace(agent.SubscriptionState) != "" {
			existing.SubscriptionState = agent.SubscriptionState
		}
		existing.AutoWakeEnabled = agent.AutoWakeEnabled
		if !existing.MachineOnline {
			existing.MachineOnline = agent.MachineOnline
		}
		merged[agent.AgentID] = existing
	}

	agents := make([]DiagnosticsAgentState, 0, len(merged))
	for _, agent := range merged {
		agents = append(agents, agent)
	}
	sort.Slice(agents, func(i, j int) bool {
		leftName := strings.ToLower(strings.TrimSpace(agents[i].AgentName))
		rightName := strings.ToLower(strings.TrimSpace(agents[j].AgentName))
		if leftName != rightName {
			return leftName < rightName
		}
		return agents[i].AgentID < agents[j].AgentID
	})
	return agents
}

func shouldOverrideDiagnosticsDeliveryReason(existing string, next string) bool {
	if strings.TrimSpace(next) == "" {
		return false
	}
	return strings.TrimSpace(existing) == ""
}

func BuildMessageDeliveryDiagnosticsAgents(message MessageDeliveryDiagnosticsMessage, routingMode string, currentScopeAgents []DiagnosticsAgentState, routedRecipients []DiagnosticsAgentState, OwnerQuoteVisibleAgentIDs map[string]struct{}, ownerPrivateRelevantAgentIDs map[string]struct{}) []MessageDeliveryDiagnosticsAgent {
	currentScopeAgentIDs := make(map[string]struct{}, len(currentScopeAgents))
	for _, agent := range currentScopeAgents {
		currentScopeAgentIDs[agent.AgentID] = struct{}{}
	}

	mergedAgents := MergeMessageDeliveryDiagnosticsAgents(currentScopeAgents, routedRecipients)
	responseAgents := make([]MessageDeliveryDiagnosticsAgent, 0, len(mergedAgents))
	for _, agent := range mergedAgents {
		if !ShouldIncludeMessageDeliveryDiagnosticsAgent(routingMode, agent, OwnerQuoteVisibleAgentIDs, ownerPrivateRelevantAgentIDs) {
			continue
		}
		targeted := strings.TrimSpace(agent.DeliveryReason) != ""
		deliveryStatus := MessageDeliveryStatusExcluded
		deliveryReason := buildMessageDeliveryExclusionReason(routingMode, message, agent)
		if targeted {
			deliveryStatus = MessageDeliveryStatusTargeted
			deliveryReason = agent.DeliveryReason
		}
		scopeStatus := MessageDeliveryScopeStatusPreviousScopeMember
		if _, ok := currentScopeAgentIDs[agent.AgentID]; ok {
			scopeStatus = MessageDeliveryScopeStatusCurrentScope
		}
		ownerPrivateState := BuildMessageDeliveryOwnerPrivateState(routingMode, message, agent, OwnerQuoteVisibleAgentIDs, ownerPrivateRelevantAgentIDs)
		wakeStatus := BuildMessageDeliveryWakeStatus(agent, targeted)

		responseAgents = append(responseAgents, MessageDeliveryDiagnosticsAgent{
			AgentID:                 agent.AgentID,
			AgentName:               agent.AgentName,
			MemberID:                agent.MemberID,
			MachineID:               agent.MachineID,
			MachineName:             agent.MachineName,
			AgentStatus:             agent.AgentStatus,
			AgentActivity:           agent.AgentActivity,
			AgentActivityDetail:     agent.ActivityDetail,
			AutoWakeEnabled:         agent.AutoWakeEnabled,
			SubscriptionState:       agent.SubscriptionState,
			MachineOnline:           agent.MachineOnline,
			ScopeStatus:             scopeStatus,
			ScopeExplanation:        ExplainMessageDeliveryScopeStatus(scopeStatus),
			DeliveryStatus:          deliveryStatus,
			DeliveryReason:          deliveryReason,
			DeliveryExplanation:     ExplainMessageDeliveryReason(deliveryReason),
			ExecutionResult:         agent.ExecutionResult,
			OwnerPrivateState:       ownerPrivateState,
			OwnerPrivateExplanation: ExplainMessageDeliveryOwnerPrivateState(ownerPrivateState),
			WakeStatus:              wakeStatus,
			WakeExplanation:         ExplainMessageDeliveryWakeStatus(wakeStatus),
		})
	}
	return responseAgents
}

func BuildMessageDeliveryOwnerPrivateRelevantAgentIDs(routingMode string, message MessageDeliveryDiagnosticsMessage, currentScopeAgents []DiagnosticsAgentState) map[string]struct{} {
	tokens := ParseDirectMentionTokens(message.Content)

	switch routingMode {
	case MessageDeliveryRoutingModeDirectMentions:
	case MessageDeliveryRoutingModeThreadReply:
		if len(tokens) == 0 {
			return nil
		}
	default:
		return nil
	}

	if len(tokens) == 0 || len(currentScopeAgents) == 0 {
		return map[string]struct{}{}
	}

	mentionedNames := make(map[string]struct{}, len(tokens))
	for _, token := range tokens {
		mentionedNames[strings.ToLower(strings.TrimSpace(token))] = struct{}{}
	}

	relevant := make(map[string]struct{})
	for _, agent := range currentScopeAgents {
		if _, ok := mentionedNames[strings.ToLower(strings.TrimSpace(agent.AgentName))]; !ok {
			continue
		}
		relevant[agent.AgentID] = struct{}{}
	}
	return relevant
}

func OwnerQuoteVisibleAgentIDs(routedRecipients []DiagnosticsAgentState, ownerQuoteVisibilityAgents []DiagnosticsAgentState) map[string]struct{} {
	visible := make(map[string]struct{})
	for _, agent := range routedRecipients {
		if agent.DeliveryReason == AgentDeliveryReasonOwnerQuote {
			visible[agent.AgentID] = struct{}{}
		}
	}
	for _, agent := range ownerQuoteVisibilityAgents {
		visible[agent.AgentID] = struct{}{}
	}
	return visible
}

func ShouldIncludeMessageDeliveryDiagnosticsAgent(routingMode string, agent DiagnosticsAgentState, OwnerQuoteVisibleAgentIDs map[string]struct{}, ownerPrivateRelevantAgentIDs map[string]struct{}) bool {
	if routingMode == MessageDeliveryRoutingModeOwnerQuote {
		return strings.TrimSpace(agent.DeliveryReason) != ""
	}
	if routingMode == MessageDeliveryRoutingModeThreadReply && strings.TrimSpace(agent.DeliveryReason) == "" {
		return false
	}
	if ownerPrivateRelevantAgentIDs == nil {
		return true
	}
	if strings.TrimSpace(agent.DeliveryReason) != "" {
		return true
	}
	if _, ok := OwnerQuoteVisibleAgentIDs[agent.AgentID]; ok {
		return true
	}
	_, ok := ownerPrivateRelevantAgentIDs[agent.AgentID]
	return ok
}

func BuildMessageDeliveryOwnerPrivateState(routingMode string, message MessageDeliveryDiagnosticsMessage, agent DiagnosticsAgentState, OwnerQuoteVisibleAgentIDs map[string]struct{}, ownerPrivateRelevantAgentIDs map[string]struct{}) string {
	switch routingMode {
	case MessageDeliveryRoutingModeOwnerQuote,
		MessageDeliveryRoutingModeBroadcastAll,
		MessageDeliveryRoutingModeBroadcastOnline:
		return ""
	}
	if !MessageUsesOwnerPrivateExplainability(message) {
		return ""
	}
	if _, ok := OwnerQuoteVisibleAgentIDs[agent.AgentID]; ok {
		return MessageDeliveryOwnerPrivateStateDeliveredByOwnerQuote
	}
	if strings.TrimSpace(agent.DeliveryReason) != "" {
		return ""
	}
	if ownerPrivateRelevantAgentIDs != nil {
		if _, ok := ownerPrivateRelevantAgentIDs[agent.AgentID]; ok {
			return MessageDeliveryOwnerPrivateStateOwnerQuoteRequired
		}
		return ""
	}
	return MessageDeliveryOwnerPrivateStateOwnerQuoteRequired
}

func buildMessageDeliveryExclusionReason(routingMode string, message MessageDeliveryDiagnosticsMessage, agent DiagnosticsAgentState) string {
	if strings.TrimSpace(agent.MemberID) == strings.TrimSpace(message.AuthorMemberID) {
		return MessageDeliveryExclusionAuthorExcluded
	}
	switch routingMode {
	case MessageDeliveryRoutingModeBroadcastAll, MessageDeliveryRoutingModeBroadcastOnline:
		authorUserID := strings.TrimSpace(message.AuthorUserID)
		if authorUserID != "" && strings.TrimSpace(agent.OwnerUserID) != authorUserID {
			return MessageDeliveryExclusionNotAuthorOwnedBroadcastAgent
		}
	}
	return ExplainMessageDeliveryExclusion(routingMode, false)
}

func MessageUsesOwnerPrivateExplainability(message MessageDeliveryDiagnosticsMessage) bool {
	if ClassifyMessageSemantics(message.MessageType, nil).RenderKind == MessageRenderOwnerQuote {
		return false
	}
	if strings.TrimSpace(message.AuthorType) != "user" && strings.TrimSpace(message.AuthorType) != "human" {
		return false
	}
	switch strings.TrimSpace(message.ChannelType) {
	case "channel", "thread":
		return true
	default:
		return false
	}
}

func ExplainMessageDeliveryExclusion(routingMode string, authorExcluded bool) string {
	if authorExcluded {
		return MessageDeliveryExclusionAuthorExcluded
	}

	switch routingMode {
	case MessageDeliveryRoutingModeSilent:
		return MessageDeliveryExclusionNoAgentScope
	case MessageDeliveryRoutingModeDirectMentions:
		return MessageDeliveryExclusionNotDirectlyMentioned
	case MessageDeliveryRoutingModeBroadcastOnline:
		return MessageDeliveryExclusionNotInOnlineSnapshot
	case MessageDeliveryRoutingModeThreadReply:
		return MessageDeliveryExclusionNotThreadParticipant
	case MessageDeliveryRoutingModeTaskCommandNotify:
		return MessageDeliveryExclusionNotTaskNotifyTarget
	case MessageDeliveryRoutingModeOwnerQuote:
		return MessageDeliveryExclusionNoCurrentScopeMembership
	case MessageDeliveryRoutingModeDM:
		return MessageDeliveryExclusionNotDMPeer
	default:
		return MessageDeliveryExclusionNoCurrentScopeMembership
	}
}

func BuildMessageDeliveryWakeStatus(agent DiagnosticsAgentState, targeted bool) string {
	if !targeted {
		return MessageDeliveryWakeSkippedNotTargeted
	}
	switch strings.TrimSpace(agent.ExecutionResult) {
	case SpaceDeliveryResultNoWake:
		return MessageDeliveryWakeSkippedNoWakeSubscription
	case SpaceDeliveryResultWake:
		return MessageDeliveryWakeWouldStartAgent
	}
	if !agent.AutoWakeEnabled {
		return MessageDeliveryWakeSkippedAutoWakeDisabled
	}
	return MessageDeliveryWakeWouldStartAgent
}

func BuildMessageDeliveryDiagnosticsSummary(agents []MessageDeliveryDiagnosticsAgent) MessageDeliveryDiagnosticsSummary {
	var summary MessageDeliveryDiagnosticsSummary
	for _, agent := range agents {
		switch agent.DeliveryStatus {
		case MessageDeliveryStatusTargeted:
			summary.TargetedAgentCount++
		case MessageDeliveryStatusExcluded:
			summary.ExcludedAgentCount++
		}

		switch agent.WakeStatus {
		case MessageDeliveryWakeWouldDeliverRunningAgent:
			summary.WakeDeliverRunningCount++
		case MessageDeliveryWakeWouldStartAgent:
			summary.WakeStartCount++
		case MessageDeliveryWakeSkippedAutoWakeDisabled,
			MessageDeliveryWakeSkippedNoWakeSubscription,
			MessageDeliveryWakeSkippedMachineOffline:
			summary.WakeBlockedCount++
		}

		if agent.OwnerPrivateState == MessageDeliveryOwnerPrivateStateOwnerQuoteRequired {
			summary.OwnerPrivateRequired = true
		}
	}
	return summary
}

func ExplainMessageDeliveryRouting(routingMode string) string {
	switch routingMode {
	case MessageDeliveryRoutingModeSilent:
		return "No agent delivery scope. This message stayed in chat only."
	case MessageDeliveryRoutingModeDirectMentions:
		return "Directly mentioned agents receive elevated wake and notification priority."
	case MessageDeliveryRoutingModeBroadcastAll:
		return "@all targets the author's agents already in this channel and wakes those on connected machines."
	case MessageDeliveryRoutingModeBroadcastOnline:
		return "@online best-effort woke the author's channel agents whose machines were connected when the message was sent."
	case MessageDeliveryRoutingModeThreadReply:
		return "Thread participants, owner-private thread agents, and newly mentioned agents stay in the scope-based receive set."
	case MessageDeliveryRoutingModeDM:
		return "Agent peers in this DM receive through the DM scope."
	case MessageDeliveryRoutingModeTaskCommandNotify:
		return "This task dispatch message notified its explicit agent targets."
	case MessageDeliveryRoutingModeOwnerQuote:
		return "The owner explicitly supplied this message as agent context."
	case MessageDeliveryRoutingModeOwnerPrivateContext:
		return "Owner-private agents configured for this target are eligible through scope membership and private authority."
	default:
		return "This message used an unrecognized routing mode."
	}
}

func ExplainMessageDeliveryReason(deliveryReason string) string {
	switch deliveryReason {
	case AgentDeliveryReasonDMPeer:
		return "This agent is a peer in the DM."
	case AgentDeliveryReasonDirectMention:
		return "This agent was directly mentioned."
	case AgentDeliveryReasonThreadParticipant:
		return "This agent is already participating in the thread."
	case AgentDeliveryReasonChannelBroadcastAll:
		return "This agent was included in the author's @all scope."
	case AgentDeliveryReasonChannelBroadcastOnline:
		return "This agent matched the author's best-effort @online wake policy at send time."
	case AgentDeliveryReasonTaskCommandNotify:
		return "This agent was explicitly notified by task dispatch."
	case AgentDeliveryReasonTaskWatch:
		return "This agent watches the task and receives its activity."
	case AgentDeliveryReasonTaskAssignee:
		return "This agent is assigned to the task."
	case AgentDeliveryReasonOwnerQuote:
		return "This agent received owner-delivered context."
	case AgentDeliveryReasonOwnerPrivateContext:
		return "This private agent is eligible through owner-private context on this target."
	case MessageDeliveryExclusionNoAgentScope:
		return "This message has no agent wake scope."
	case MessageDeliveryExclusionNotDirectlyMentioned:
		return "This agent was not directly mentioned."
	case MessageDeliveryExclusionNotInOnlineSnapshot:
		return "This agent was not selected for the best-effort @online wake policy."
	case MessageDeliveryExclusionNotThreadParticipant:
		return "This agent was not a thread participant and was not newly mentioned."
	case MessageDeliveryExclusionNotTaskNotifyTarget:
		return "This agent was not in the task dispatch target set."
	case MessageDeliveryExclusionNotDMPeer:
		return "This agent is not a peer in the DM."
	case MessageDeliveryExclusionAuthorExcluded:
		return "Authors are excluded from agent wake fanout."
	case MessageDeliveryExclusionNoCurrentScopeMembership:
		return "This agent is not an active member of the current message scope."
	case MessageDeliveryExclusionNotAuthorOwnedBroadcastAgent:
		return "Controlled broadcast targets only the author's channel agents."
	default:
		return "This message produced an unrecognized delivery reason."
	}
}

func ExplainMessageDeliveryOwnerPrivateState(ownerPrivateState string) string {
	switch ownerPrivateState {
	case MessageDeliveryOwnerPrivateStateDeliveredByOwnerQuote:
		return "Delivered by owner"
	case MessageDeliveryOwnerPrivateStateOwnerQuoteRequired:
		return "Not delivered: owner delivery required"
	default:
		return ""
	}
}

func ExplainMessageDeliveryWakeStatus(wakeStatus string) string {
	switch wakeStatus {
	case MessageDeliveryWakeWouldDeliverRunningAgent:
		return "Included, and the current daemon connection would receive the message if the agent is still running."
	case MessageDeliveryWakeWouldStartAgent:
		return "Included, and AgentTeam would attempt to wake or start the agent on the current daemon connection."
	case MessageDeliveryWakeSkippedNotTargeted:
		return "Not included in the wake set, so wake was skipped."
	case MessageDeliveryWakeSkippedAutoWakeDisabled:
		return "Included, but auto wake is disabled."
	case MessageDeliveryWakeSkippedNoWakeSubscription:
		return "This agent can receive the message through scope membership, but notification settings are set to no-wake."
	case MessageDeliveryWakeSkippedMachineOffline:
		return "Included, but no daemon connection was available when this status was recorded."
	default:
		return "This agent produced an unrecognized wake status."
	}
}

func ExplainMessageDeliveryContextScope(contextScope string) string {
	switch contextScope {
	case MessageDeliveryContextScopeChannelMainline:
		return "Handling should use this channel's mainline history only. Reply threads stay outside this context."
	case MessageDeliveryContextScopeThread:
		return "Handling should use this reply thread's history plus the parent reference. Parent mainline history stays outside this context."
	case MessageDeliveryContextScopeDM:
		return "Handling should use this DM history only."
	default:
		return "This message used an unrecognized context scope."
	}
}

func ExplainMessageDeliveryScopeStatus(scopeStatus string) string {
	switch scopeStatus {
	case MessageDeliveryScopeStatusCurrentScope:
		return "This agent is still inside the current message scope."
	case MessageDeliveryScopeStatusPreviousScopeMember:
		return "This agent is no longer inside the current message scope; diagnostics do not treat prior membership as a delivery fact."
	default:
		return "This agent used an unrecognized scope status."
	}
}

func ExplainMessageDeliveryWakeInference(wakeInferenceBasis string) string {
	switch wakeInferenceBasis {
	case MessageDeliveryWakeInferenceCurrentRuntime:
		return "Wake outcomes are inferred from current machine and agent state, not from a persisted historical wake log."
	case MessageDeliveryWakeInferenceOutboxState:
		return "Fanout reliability is reported from outbox state and errors; message visibility still comes from scope membership and cursors."
	default:
		return "Wake outcomes use an unrecognized inference basis."
	}
}

type DeliverySummaryMessage struct {
	ID             string
	AuthorMemberID string
	AuthorUserID   string
	AuthorType     string
	MessageType    string
	Content        string
}

type DeliverySummaryPreview struct {
	TargetedAgentCount int
	ExcludedAgentCount int
	ActiveNowCount     int
}

type DeliverySummaryPreviewState struct {
	Preview            *DeliverySummaryPreview
	DiagnosticsEnabled *bool
}

func DeriveMessageDiagnosticsRecipientsFromScope(message MessageDeliveryDiagnosticsMessage, currentScopeAgents []DiagnosticsAgentState) []DiagnosticsAgentState {
	if len(currentScopeAgents) == 0 {
		return nil
	}
	reasonByAgentID := make(map[string]string)
	assignAll := func(reason string) {
		for _, agent := range currentScopeAgents {
			if strings.TrimSpace(agent.MemberID) == strings.TrimSpace(message.AuthorMemberID) {
				continue
			}
			reasonByAgentID[agent.AgentID] = reason
		}
	}
	assignOwnedBroadcast := func(reason string) {
		authorUserID := strings.TrimSpace(message.AuthorUserID)
		if authorUserID == "" {
			return
		}
		for _, agent := range currentScopeAgents {
			if strings.TrimSpace(agent.MemberID) == strings.TrimSpace(message.AuthorMemberID) {
				continue
			}
			if strings.TrimSpace(agent.OwnerUserID) != authorUserID {
				continue
			}
			reasonByAgentID[agent.AgentID] = reason
		}
	}

	switch strings.TrimSpace(message.ChannelType) {
	case "dm":
		assignAll(AgentDeliveryReasonDMPeer)
	case "thread":
		assignAll(AgentDeliveryReasonThreadParticipant)
	default:
		hasControlledBroadcastMode := false
		if messageSupportsControlledBroadcast(message) {
			if broadcastMode, err := ParseControlledBroadcastMode(message.Content); err == nil {
				switch broadcastMode {
				case ChannelBroadcastModeAll:
					hasControlledBroadcastMode = true
					assignOwnedBroadcast(AgentDeliveryReasonChannelBroadcastAll)
				case ChannelBroadcastModeOnline:
					hasControlledBroadcastMode = true
					assignOwnedBroadcast(AgentDeliveryReasonChannelBroadcastOnline)
				}
			}
		}
		if !hasControlledBroadcastMode && len(reasonByAgentID) == 0 {
			assignAll(AgentDeliveryReasonSpaceDefault)
		}
	}

	mentionedTokens := normalizeMentionTokens(ParseDirectMentionTokens(message.Content))
	if len(mentionedTokens) > 0 {
		for _, agent := range currentScopeAgents {
			if strings.TrimSpace(agent.MemberID) == strings.TrimSpace(message.AuthorMemberID) {
				continue
			}
			if _, ok := mentionedTokens[strings.ToLower(strings.TrimSpace(agent.AgentName))]; ok {
				reasonByAgentID[agent.AgentID] = AgentDeliveryReasonDirectMention
				continue
			}
			if _, ok := mentionedTokens[strings.ToLower(strings.TrimSpace(agent.MemberID))]; ok {
				reasonByAgentID[agent.AgentID] = AgentDeliveryReasonDirectMention
			}
		}
	}

	recipients := make([]DiagnosticsAgentState, 0, len(reasonByAgentID))
	for _, agent := range currentScopeAgents {
		reason := strings.TrimSpace(reasonByAgentID[agent.AgentID])
		if reason == "" {
			continue
		}
		derived := agent
		derived.DeliveryReason = reason
		switch reason {
		case AgentDeliveryReasonDirectMention, AgentDeliveryReasonChannelBroadcastAll, AgentDeliveryReasonChannelBroadcastOnline, AgentDeliveryReasonTaskCommandNotify, AgentDeliveryReasonTaskAssignee, AgentDeliveryReasonOwnerQuote, AgentDeliveryReasonOwnerPrivateContext:
			derived.ExecutionResult = SpaceDeliveryResultWake
		default:
			derived.ExecutionResult = SpaceDeliveryResultNoWake
			if agent.AutoWakeEnabled {
				derived.ExecutionResult = SpaceDeliveryResultWake
			}
		}
		recipients = append(recipients, derived)
	}
	return recipients
}

func normalizeMentionTokens(tokens []string) map[string]struct{} {
	normalized := make(map[string]struct{}, len(tokens))
	for _, token := range tokens {
		token = strings.ToLower(strings.TrimSpace(token))
		if token == "" {
			continue
		}
		normalized[token] = struct{}{}
	}
	return normalized
}

func BuildDeliverySummaryPreviewState(message DeliverySummaryMessage, channelType string, currentScopeAgents []DiagnosticsAgentState, routedRecipients []DiagnosticsAgentState) DeliverySummaryPreviewState {
	diagnosticsMessage := MessageDeliveryDiagnosticsMessage{
		ID:             strings.TrimSpace(message.ID),
		ChannelType:    strings.TrimSpace(channelType),
		AuthorMemberID: strings.TrimSpace(message.AuthorMemberID),
		AuthorUserID:   strings.TrimSpace(message.AuthorUserID),
		MessageType:    strings.TrimSpace(message.MessageType),
		Content:        message.Content,
	}
	routingMode := DetectMessageDeliveryRoutingMode(diagnosticsMessage, routedRecipients)
	ownerPrivateRelevantAgentIDs := BuildMessageDeliveryOwnerPrivateRelevantAgentIDs(
		routingMode,
		diagnosticsMessage,
		currentScopeAgents,
	)
	agents := BuildMessageDeliveryDiagnosticsAgents(
		diagnosticsMessage,
		routingMode,
		currentScopeAgents,
		routedRecipients,
		nil,
		ownerPrivateRelevantAgentIDs,
	)
	previewAgents := FilterDeliverySummaryAgents(message, agents)
	if ShouldSuppressDeliverySummaryDiagnostics(
		channelType,
		message,
		routingMode,
		routedRecipients,
		ownerPrivateRelevantAgentIDs,
	) {
		return DeliverySummaryPreviewState{
			DiagnosticsEnabled: boolPointer(false),
		}
	}

	preview := DeliverySummaryPreview{
		ActiveNowCount: DeliverySummaryActiveNowCount(previewAgents),
	}
	summary := BuildMessageDeliveryDiagnosticsSummary(previewAgents)
	preview.TargetedAgentCount = summary.TargetedAgentCount
	preview.ExcludedAgentCount = summary.ExcludedAgentCount

	if strings.TrimSpace(message.AuthorType) == "agent" && preview.TargetedAgentCount == 0 {
		return DeliverySummaryPreviewState{}
	}
	if !ShouldShowDeliverySummaryPreview(preview) {
		return DeliverySummaryPreviewState{}
	}
	return DeliverySummaryPreviewState{
		Preview: &preview,
	}
}

func BuildDeliverySummaryPreview(message DeliverySummaryMessage, channelType string, currentScopeAgents []DiagnosticsAgentState, routedRecipients []DiagnosticsAgentState) *DeliverySummaryPreview {
	return BuildDeliverySummaryPreviewState(
		message,
		channelType,
		currentScopeAgents,
		routedRecipients,
	).Preview
}

func ShouldSuppressDeliverySummaryDiagnostics(channelType string, message DeliverySummaryMessage, routingMode string, routedRecipients []DiagnosticsAgentState, ownerPrivateRelevantAgentIDs map[string]struct{}) bool {
	authorType := strings.TrimSpace(message.AuthorType)
	if authorType != "user" && authorType != "human" {
		return false
	}
	if strings.TrimSpace(channelType) != "channel" {
		return false
	}
	if len(routedRecipients) != 0 {
		return false
	}
	if len(ownerPrivateRelevantAgentIDs) == 0 {
		return false
	}
	switch routingMode {
	case MessageDeliveryRoutingModeDirectMentions, MessageDeliveryRoutingModeThreadReply:
		return true
	default:
		return false
	}
}

func FilterDeliverySummaryAgents(message DeliverySummaryMessage, agents []MessageDeliveryDiagnosticsAgent) []MessageDeliveryDiagnosticsAgent {
	if len(agents) == 0 {
		return nil
	}

	authorMemberID := strings.TrimSpace(message.AuthorMemberID)
	if authorMemberID == "" {
		return agents
	}

	filtered := make([]MessageDeliveryDiagnosticsAgent, 0, len(agents))
	for _, agent := range agents {
		if strings.TrimSpace(agent.MemberID) == authorMemberID {
			continue
		}
		filtered = append(filtered, agent)
	}
	return filtered
}

func ShouldShowDeliverySummaryPreview(preview DeliverySummaryPreview) bool {
	return preview.TargetedAgentCount > 0 ||
		preview.ExcludedAgentCount > 0
}

func DeliverySummaryActiveNowCount(agents []MessageDeliveryDiagnosticsAgent) int {
	count := 0
	for _, agent := range agents {
		switch NormalizeDeliverySummaryActivity(agent.AgentActivity, agent.AgentStatus) {
		case "thinking", "working":
			count++
		}
	}
	return count
}

func NormalizeDeliverySummaryActivity(activity string, status string) string {
	return normalizeDeliverySummaryActivity(activity, status)
}

func boolPointer(value bool) *bool {
	return &value
}

func normalizeDeliverySummaryActivity(activity string, status string) string {
	switch strings.TrimSpace(activity) {
	case "sleeping", "online":
		return "online"
	case "thinking":
		return "thinking"
	case "working":
		return "working"
	}

	switch strings.TrimSpace(status) {
	case "sleeping":
		return "online"
	case "active":
		return "working"
	default:
		return "offline"
	}
}
