package message

import (
	"testing"

	"github.com/stretchr/testify/require"
)

func TestExplainMessageDeliveryRoutingReturnsOperatorCopy(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name        string
		routingMode string
		want        string
	}{
		{
			name:        "silent",
			routingMode: MessageDeliveryRoutingModeSilent,
			want:        "No agent delivery scope. This message stayed in chat only.",
		},
		{
			name:        "direct mentions",
			routingMode: MessageDeliveryRoutingModeDirectMentions,
			want:        "Directly mentioned agents receive elevated wake and notification priority.",
		},
		{
			name:        "broadcast all",
			routingMode: MessageDeliveryRoutingModeBroadcastAll,
			want:        "@all targets the author's agents already in this channel and wakes those on connected machines.",
		},
		{
			name:        "broadcast online",
			routingMode: MessageDeliveryRoutingModeBroadcastOnline,
			want:        "@online best-effort woke the author's channel agents whose machines were connected when the message was sent.",
		},
		{
			name:        "thread reply",
			routingMode: MessageDeliveryRoutingModeThreadReply,
			want:        "Thread participants, owner-private thread agents, and newly mentioned agents stay in the scope-based receive set.",
		},
		{
			name:        "dm",
			routingMode: MessageDeliveryRoutingModeDM,
			want:        "Agent peers in this DM receive through the DM scope.",
		},
		{
			name:        "task command notify",
			routingMode: MessageDeliveryRoutingModeTaskCommandNotify,
			want:        "This task dispatch message notified its explicit agent targets.",
		},
		{
			name:        "owner quote",
			routingMode: MessageDeliveryRoutingModeOwnerQuote,
			want:        "The owner explicitly supplied this message as agent context.",
		},
		{
			name:        "owner-private context",
			routingMode: MessageDeliveryRoutingModeOwnerPrivateContext,
			want:        "Owner-private agents configured for this target are eligible through scope membership and private authority.",
		},
		{
			name:        "unknown",
			routingMode: "mystery",
			want:        "This message used an unrecognized routing mode.",
		},
	}

	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			require.Equal(t, test.want, ExplainMessageDeliveryRouting(test.routingMode))
		})
	}
}

func TestExplainMessageDeliveryReasonReturnsOperatorCopy(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name           string
		deliveryReason string
		want           string
	}{
		{
			name:           "dm peer",
			deliveryReason: AgentDeliveryReasonDMPeer,
			want:           "This agent is a peer in the DM.",
		},
		{
			name:           "direct mention",
			deliveryReason: AgentDeliveryReasonDirectMention,
			want:           "This agent was directly mentioned.",
		},
		{
			name:           "thread participant",
			deliveryReason: AgentDeliveryReasonThreadParticipant,
			want:           "This agent is already participating in the thread.",
		},
		{
			name:           "channel broadcast all",
			deliveryReason: AgentDeliveryReasonChannelBroadcastAll,
			want:           "This agent was included in the author's @all scope.",
		},
		{
			name:           "channel broadcast online",
			deliveryReason: AgentDeliveryReasonChannelBroadcastOnline,
			want:           "This agent matched the author's best-effort @online wake policy at send time.",
		},
		{
			name:           "task notify",
			deliveryReason: AgentDeliveryReasonTaskCommandNotify,
			want:           "This agent was explicitly notified by task dispatch.",
		},
		{
			name:           "task watch",
			deliveryReason: AgentDeliveryReasonTaskWatch,
			want:           "This agent watches the task and receives its activity.",
		},
		{
			name:           "task assignee",
			deliveryReason: AgentDeliveryReasonTaskAssignee,
			want:           "This agent is assigned to the task.",
		},
		{
			name:           "owner quote",
			deliveryReason: AgentDeliveryReasonOwnerQuote,
			want:           "This agent received owner-delivered context.",
		},
		{
			name:           "owner-private context",
			deliveryReason: AgentDeliveryReasonOwnerPrivateContext,
			want:           "This private agent is eligible through owner-private context on this target.",
		},
		{
			name:           "no agent scope",
			deliveryReason: MessageDeliveryExclusionNoAgentScope,
			want:           "This message has no agent wake scope.",
		},
		{
			name:           "not directly mentioned",
			deliveryReason: MessageDeliveryExclusionNotDirectlyMentioned,
			want:           "This agent was not directly mentioned.",
		},
		{
			name:           "not online active",
			deliveryReason: MessageDeliveryExclusionNotOnlineActive,
			want:           "This agent was not selected for the best-effort @online wake policy.",
		},
		{
			name:           "not thread participant",
			deliveryReason: MessageDeliveryExclusionNotThreadParticipant,
			want:           "This agent was not a thread participant and was not newly mentioned.",
		},
		{
			name:           "not task notify target",
			deliveryReason: MessageDeliveryExclusionNotTaskNotifyTarget,
			want:           "This agent was not in the task dispatch target set.",
		},
		{
			name:           "not dm peer",
			deliveryReason: MessageDeliveryExclusionNotDMPeer,
			want:           "This agent is not a peer in the DM.",
		},
		{
			name:           "author excluded",
			deliveryReason: MessageDeliveryExclusionAuthorExcluded,
			want:           "Authors are excluded from agent wake fanout.",
		},
		{
			name:           "no current scope membership",
			deliveryReason: MessageDeliveryExclusionNoCurrentScopeMembership,
			want:           "This agent is not an active member of the current message scope.",
		},
		{
			name:           "not author owned broadcast agent",
			deliveryReason: MessageDeliveryExclusionNotAuthorOwnedBroadcastAgent,
			want:           "Controlled broadcast targets only the author's channel agents.",
		},
		{
			name:           "unknown",
			deliveryReason: "mystery",
			want:           "This message produced an unrecognized delivery reason.",
		},
	}

	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			require.Equal(t, test.want, ExplainMessageDeliveryReason(test.deliveryReason))
		})
	}
}

func TestExplainMessageDeliveryOwnerPrivateStateReturnsProductCopy(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name              string
		ownerPrivateState string
		want              string
	}{
		{
			name:              "delivered by owner quote",
			ownerPrivateState: MessageDeliveryOwnerPrivateStateDeliveredByOwnerQuote,
			want:              "Delivered by owner",
		},
		{
			name:              "owner quote required",
			ownerPrivateState: MessageDeliveryOwnerPrivateStateOwnerQuoteRequired,
			want:              "Not delivered: owner delivery required",
		},
		{
			name:              "unknown",
			ownerPrivateState: "mystery",
			want:              "",
		},
	}

	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			require.Equal(t, test.want, ExplainMessageDeliveryOwnerPrivateState(test.ownerPrivateState))
		})
	}
}

func TestExplainMessageDeliveryWakeStatusReturnsOperatorCopy(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name       string
		wakeStatus string
		want       string
	}{
		{
			name:       "deliver running agent",
			wakeStatus: MessageDeliveryWakeWouldDeliverRunningAgent,
			want:       "Included, and the current daemon connection would receive the message if the agent is still running.",
		},
		{
			name:       "start agent",
			wakeStatus: MessageDeliveryWakeWouldStartAgent,
			want:       "Included, and AgentTeam would attempt to wake or start the agent on the current daemon connection.",
		},
		{
			name:       "not targeted",
			wakeStatus: MessageDeliveryWakeSkippedNotTargeted,
			want:       "Not included in the wake set, so wake was skipped.",
		},
		{
			name:       "auto wake disabled",
			wakeStatus: MessageDeliveryWakeSkippedAutoWakeDisabled,
			want:       "Included, but auto wake is disabled.",
		},
		{
			name:       "no-wake subscription",
			wakeStatus: MessageDeliveryWakeSkippedNoWakeSubscription,
			want:       "This agent can receive the message through scope membership, but notification settings are set to no-wake.",
		},
		{
			name:       "machine offline",
			wakeStatus: MessageDeliveryWakeSkippedMachineOffline,
			want:       "Included, but no daemon connection was available when this status was recorded.",
		},
		{
			name:       "unknown",
			wakeStatus: "mystery",
			want:       "This agent produced an unrecognized wake status.",
		},
	}

	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			require.Equal(t, test.want, ExplainMessageDeliveryWakeStatus(test.wakeStatus))
		})
	}
}

func TestExplainMessageDeliveryWakeInferenceReturnsOperatorCopy(t *testing.T) {
	t.Parallel()

	require.Equal(
		t,
		"Wake outcomes are inferred from current machine and agent state, not from a persisted historical wake log.",
		ExplainMessageDeliveryWakeInference(MessageDeliveryWakeInferenceCurrentRuntime),
	)
	require.Equal(
		t,
		"Wake outcomes use an unrecognized inference basis.",
		ExplainMessageDeliveryWakeInference("mystery"),
	)
}

func TestDetectMessageDeliveryContextScopeReturnsOperatorContext(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name    string
		message MessageDeliveryDiagnosticsMessage
		want    string
	}{
		{
			name: "channel mainline",
			message: MessageDeliveryDiagnosticsMessage{
				ChannelType: "channel",
			},
			want: MessageDeliveryContextScopeChannelMainline,
		},
		{
			name: "dm mainline",
			message: MessageDeliveryDiagnosticsMessage{
				ChannelType: "dm",
			},
			want: MessageDeliveryContextScopeDM,
		},
		{
			name: "thread under channel stays thread scoped",
			message: MessageDeliveryDiagnosticsMessage{
				ChannelType:       "thread",
				ParentChannelType: "channel",
			},
			want: MessageDeliveryContextScopeThread,
		},
		{
			name: "thread under dm stays thread scoped",
			message: MessageDeliveryDiagnosticsMessage{
				ChannelType:       "thread",
				ParentChannelType: "dm",
			},
			want: MessageDeliveryContextScopeThread,
		},
	}

	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			require.Equal(t, test.want, DetectMessageDeliveryContextScope(test.message))
		})
	}
}

func TestExplainMessageDeliveryScopeStatusReturnsOperatorCopy(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name        string
		scopeStatus string
		want        string
	}{
		{
			name:        "current scope",
			scopeStatus: MessageDeliveryScopeStatusCurrentScope,
			want:        "This agent is still inside the current message scope.",
		},
		{
			name:        "previous scope member",
			scopeStatus: MessageDeliveryScopeStatusPreviousScopeMember,
			want:        "This agent is no longer inside the current message scope; diagnostics do not treat prior membership as a delivery fact.",
		},
		{
			name:        "unknown",
			scopeStatus: "mystery",
			want:        "This agent used an unrecognized scope status.",
		},
	}

	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			require.Equal(t, test.want, ExplainMessageDeliveryScopeStatus(test.scopeStatus))
		})
	}
}

func TestExplainMessageDeliveryContextScopeReturnsOperatorCopy(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name         string
		contextScope string
		want         string
	}{
		{
			name:         "channel mainline",
			contextScope: MessageDeliveryContextScopeChannelMainline,
			want:         "Handling should use this channel's mainline history only. Reply threads stay outside this context.",
		},
		{
			name:         "thread",
			contextScope: MessageDeliveryContextScopeThread,
			want:         "Handling should use this reply thread's history plus the parent reference. Parent mainline history stays outside this context.",
		},
		{
			name:         "dm",
			contextScope: MessageDeliveryContextScopeDM,
			want:         "Handling should use this DM history only.",
		},
		{
			name:         "unknown",
			contextScope: "mystery",
			want:         "This message used an unrecognized context scope.",
		},
	}

	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			require.Equal(t, test.want, ExplainMessageDeliveryContextScope(test.contextScope))
		})
	}
}
