package routing

import (
	"strings"
	"testing"

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

func TestParseDirectMentionTokensIgnoresCodeAndBroadcastTokens(t *testing.T) {
	content := "hello @alpha-agent @all `@inline-agent`\n```\n@code-agent\n```\n@online @beta-agent"
	require.Equal(t, []string{"alpha-agent", "beta-agent"}, ParseDirectMentionTokens(content))
}

func TestParseDirectMentionTokensIgnoresWordJoinerEscapedAt(t *testing.T) {
	require.Empty(t, ParseDirectMentionTokens("Review @\u2060build-agent"))
}

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

	tests := []struct {
		name       string
		content    string
		wantTokens []string
		wantMode   ChannelBroadcastMode
	}{
		{
			name:       "direct mention inert",
			content:    "literal `code starts\n@alpha-agent stays inert\ncode ends` then @beta-agent is live",
			wantTokens: []string{"beta-agent"},
			wantMode:   ChannelBroadcastModeNone,
		},
		{
			name:       "all broadcast inert",
			content:    "literal `code starts\n@all stays inert\ncode ends` then @online is live",
			wantTokens: []string{"online"},
			wantMode:   ChannelBroadcastModeOnline,
		},
		{
			name:       "online broadcast inert",
			content:    "literal `code starts\n@online stays inert\ncode ends` then @all is live",
			wantTokens: []string{"all"},
			wantMode:   ChannelBroadcastModeAll,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			require.Equal(t, tt.wantTokens, ParseMentionTokens(tt.content))
			mode, err := ParseControlledBroadcastMode(tt.content)
			require.NoError(t, err)
			require.Equal(t, tt.wantMode, mode)
		})
	}
}

func TestParseDirectMentionTokensIgnoresBlockquotes(t *testing.T) {
	content := "> ping @quoted-agent\n\nplease wake @alpha-agent"
	require.Equal(t, []string{"alpha-agent"}, ParseDirectMentionTokens(content))
}

func TestParseDirectMentionTokensSupportsUnicodeTokens(t *testing.T) {
	content := "请 @调研专家 和 @助手-2 看看"
	require.Equal(t, []string{"调研专家", "助手-2"}, ParseDirectMentionTokens(content))
}

func TestParseDirectMentionTokensRequiresWhitespaceBoundary(t *testing.T) {
	content := "@alpha please help\nhello @beta\n@alpha@shadow\nssh root@xxx\nmail foo@example.com\nscp a@b:/tmp\n请@调研专家"
	require.Equal(t, []string{"alpha", "beta"}, ParseDirectMentionTokens(content))
}

func TestParseDirectMentionTokensLimitBoundsUniqueDirectTokens(t *testing.T) {
	content := "@all @alpha @beta @alpha @online @gamma @delta"
	require.Equal(t, []string{"alpha", "beta"}, ParseDirectMentionTokensLimit(content, 2))
	require.Equal(t, []string{"alpha", "beta", "gamma", "delta"}, ParseDirectMentionTokensLimit(content, 0))
}

func TestParseDirectMentionSpansPreservesSourceIdentityAndByteOffsets(t *testing.T) {
	content := "请 @调研/专家 看 [@alice](/mentions/service/member%2F2) and @调研/专家"
	require.Equal(t, []DirectMentionSpan{
		{Token: "调研/专家", Start: 4, End: 18},
		{Token: "alice", Type: "service", ID: "member/2", Start: 24, End: 30},
		{Token: "调研/专家", Start: 66, End: 80},
	}, ParseDirectMentionSpansLimit(content, 0))
}

func TestParseDirectMentionSpansUsesInertSyntaxAndIdentityLimit(t *testing.T) {
	content := strings.Join([]string{
		"> quote @quoted",
		">text @live",
		"`@inline` @alpha",
		"```",
		"@fenced",
		"```",
		"[@same](/mentions/service/m1) [@same](/mentions/service/m1)",
		"[@same](/mentions/service/m2) @beta @all @online",
	}, "\n")

	spans := ParseDirectMentionSpansLimit(content, 3)
	require.Len(t, spans, 4)
	type identity struct{ token, mentionType, id string }
	identities := make([]identity, 0, len(spans))
	for _, span := range spans {
		identities = append(identities, identity{span.Token, span.Type, span.ID})
	}
	require.Equal(t, []identity{
		{token: "live"},
		{token: "alpha"},
		{token: "same", mentionType: "service", id: "m1"},
		{token: "same", mentionType: "service", id: "m1"},
	}, identities)
}

func TestParseControlledBroadcastModeRejectsConflictingModes(t *testing.T) {
	_, err := ParseControlledBroadcastMode("ping @all and @online")
	require.Error(t, err)

	mode, err := ParseControlledBroadcastMode("ping @online")
	require.NoError(t, err)
	require.Equal(t, ChannelBroadcastModeOnline, mode)
}
