package app

import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/core/routing"
)

func TestAppMentionLookupKeysAndCandidateMatchingUseIdentity(t *testing.T) {
	spans := []routing.DirectMentionSpan{
		{Token: "alice", Type: "service", ID: "m2", Start: 1, End: 7},
		{Token: "builder", Start: 40, End: 48},
	}
	keys := appMentionLookupKeysForSpans(spans)
	require.Equal(t, []string{"builder"}, keys.Tokens)
	require.Equal(t, []string{"m2"}, keys.MemberIDs)

	m1 := appMentionSubscriptionCandidate{
		ServiceMemberMemberID: "m1",
		ServiceMemberHandle:   "alice",
	}
	m2 := appMentionSubscriptionCandidate{
		ServiceMemberMemberID: "m2",
		ServiceMemberHandle:   "different-handle",
	}
	require.Empty(t, appMentionSpansForCandidate(spans, m1))
	require.Equal(t, spans[:1], appMentionSpansForCandidate(spans, m2))
}

func TestAppMentionLookupKeysCTESupportsOnlyAndRawOnly(t *testing.T) {
	for _, keys := range []appMentionLookupKeys{
		{MemberIDs: []string{"m2"}},
		{Tokens: []string{"builder"}},
	} {
		query, args, nextArg, err := appMentionLookupKeysCTE(keys, 4)
		require.NoError(t, err)
		require.Contains(t, query, "mentioned_tokens AS")
		require.Contains(t, query, "mentioned_member_ids AS")
		require.Len(t, args, 1)
		require.Equal(t, 5, nextArg)
	}
}

func TestMergeAppMentionThreadTargetCandidatesUsesOneGlobalLockOrder(t *testing.T) {
	parentCandidates := []appMentionThreadTargetCandidate{
		{
			ServiceDefinitionID:   "app_b",
			ServiceInstallationID: "inst_b",
			ServiceMemberMemberID: "mem_b",
			ParentAuthority:       true,
		},
		{
			ServiceDefinitionID:   "app_c",
			ServiceInstallationID: "inst_c",
			ServiceMemberMemberID: "mem_c",
			ParentAuthority:       true,
		},
	}
	directCandidates := []appMentionThreadTargetCandidate{
		{
			ServiceDefinitionID:   "app_a",
			ServiceInstallationID: "inst_a",
			ServiceMemberMemberID: "mem_a",
			DirectTargetAuthority: true,
		},
		{
			ServiceDefinitionID:   "app_c",
			ServiceInstallationID: "inst_c",
			ServiceMemberMemberID: "mem_c",
			DirectTargetAuthority: true,
		},
	}

	got := mergeAppMentionThreadTargetCandidates(parentCandidates, directCandidates)
	require.Equal(t, []appMentionThreadTargetCandidate{
		{
			ServiceDefinitionID:   "app_a",
			ServiceInstallationID: "inst_a",
			ServiceMemberMemberID: "mem_a",
			DirectTargetAuthority: true,
		},
		{
			ServiceDefinitionID:   "app_b",
			ServiceInstallationID: "inst_b",
			ServiceMemberMemberID: "mem_b",
			ParentAuthority:       true,
		},
		{
			ServiceDefinitionID:   "app_c",
			ServiceInstallationID: "inst_c",
			ServiceMemberMemberID: "mem_c",
			ParentAuthority:       true,
			DirectTargetAuthority: true,
		},
	}, got)
}

func TestMergeAppMentionThreadTargetCandidatesRejectsConflictingIdentity(t *testing.T) {
	got := mergeAppMentionThreadTargetCandidates(
		[]appMentionThreadTargetCandidate{{
			ServiceDefinitionID:   "app_a",
			ServiceInstallationID: "inst_shared",
			ServiceMemberMemberID: "mem_a",
			ParentAuthority:       true,
		}},
		[]appMentionThreadTargetCandidate{{
			ServiceDefinitionID:   "app_b",
			ServiceInstallationID: "inst_shared",
			ServiceMemberMemberID: "mem_b",
			DirectTargetAuthority: true,
		}},
	)
	require.Empty(t, got)
}
