package runtime

import (
	"github.com/tidbcloud/AgentTeam/internal/knowledgeqa/protocol"

	"context"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/AgentTeam/internal/store/content"
	"github.com/tidbcloud/AgentTeam/internal/store/kb"
	"github.com/tidbcloud/AgentTeam/internal/store/resource/repos"
	"gorm.io/gorm"
)

type fakeWorkspaceAccess struct {
	allowed bool
}

func (access fakeWorkspaceAccess) HasWorkspaceAccess(context.Context, string, string) (bool, error) {
	return access.allowed, nil
}

type fakeKnowledgeRootStore struct {
	bases                        []kb.KnowledgeBase
	grants                       []kb.KnowledgeBaseGrant
	sources                      []kb.Source
	revisions                    map[string]kb.SourceRevision
	mappings                     map[string]kb.SourceContentMapping
	overrides                    []kb.KnowledgeBaseSourceRepositoryAccessOverride
	mirrors                      map[string]kb.SourceMirror
	listKnowledgeBasesCalls      *int
	listKnowledgeBasesByIDsCalls *int
	listSourcesForKnowledgeCalls *int
	listSourcesByIDsCalls        *int
	listSourceRevisionsCalls     *int
	listSourceMirrorsCalls       *int
}

func (store fakeKnowledgeRootStore) ListKnowledgeBaseSourceRepositoryAccessOverridesForSources(_ context.Context, workspaceID string, grantIDs, sourceIDs []string) ([]kb.KnowledgeBaseSourceRepositoryAccessOverride, error) {
	grants := stringSet(grantIDs)
	sources := stringSet(sourceIDs)
	rows := make([]kb.KnowledgeBaseSourceRepositoryAccessOverride, 0)
	for _, row := range store.overrides {
		if row.WorkspaceID == workspaceID {
			if _, ok := grants[row.GrantID]; ok {
				if _, ok := sources[row.SourceID]; ok {
					rows = append(rows, row)
				}
			}
		}
	}
	return rows, nil
}

func (store fakeKnowledgeRootStore) ListSourceContentMappingsForRevisions(_ context.Context, workspaceID string, revisionIDs []string) ([]kb.SourceContentMapping, error) {
	selected := stringSet(revisionIDs)
	rows := make([]kb.SourceContentMapping, 0, len(revisionIDs))
	for revisionID, mapping := range store.mappings {
		if _, ok := selected[revisionID]; !ok {
			continue
		}
		if mapping.SourceRevisionID == "" {
			mapping.SourceRevisionID = revisionID
		}
		if mapping.WorkspaceID == "" {
			mapping.WorkspaceID = workspaceID
		}
		rows = append(rows, mapping)
	}
	return rows, nil
}

func (store fakeKnowledgeRootStore) GetSourceContentMappingByVersion(_ context.Context, workspaceID, sourceID, versionID string) (kb.SourceContentMapping, error) {
	for _, mapping := range store.mappings {
		if mapping.WorkspaceID == workspaceID && mapping.SourceID == sourceID && mapping.ContentVersionID == versionID {
			return mapping, nil
		}
	}
	return kb.SourceContentMapping{}, kb.ErrSourceContentMappingNotFound
}

func (store fakeKnowledgeRootStore) ListKnowledgeBases(_ context.Context, _ string, _ string, _ bool, page, perPage int) ([]kb.KnowledgeBase, error) {
	if store.listKnowledgeBasesCalls != nil {
		(*store.listKnowledgeBasesCalls)++
	}
	if page <= 0 {
		page = 1
	}
	if perPage <= 0 {
		perPage = len(store.bases)
	}
	start := (page - 1) * perPage
	if start >= len(store.bases) {
		return []kb.KnowledgeBase{}, nil
	}
	end := start + perPage
	if end > len(store.bases) {
		end = len(store.bases)
	}
	return append([]kb.KnowledgeBase(nil), store.bases[start:end]...), nil
}

func (store fakeKnowledgeRootStore) ListOfficialKnowledgeBases(_ context.Context, _ string, page, perPage int) ([]kb.KnowledgeBase, error) {
	official := make([]kb.KnowledgeBase, 0, len(store.bases))
	for _, base := range store.bases {
		if strings.TrimSpace(base.PublicationState) == "draft" {
			continue
		}
		official = append(official, base)
	}
	start := (page - 1) * perPage
	if start >= len(official) {
		return []kb.KnowledgeBase{}, nil
	}
	end := start + perPage
	if end > len(official) {
		end = len(official)
	}
	return append([]kb.KnowledgeBase(nil), official[start:end]...), nil
}

func (store fakeKnowledgeRootStore) ListKnowledgeBasesByIDs(_ context.Context, workspaceID string, knowledgeBaseIDs []string) ([]kb.KnowledgeBase, error) {
	if store.listKnowledgeBasesByIDsCalls != nil {
		(*store.listKnowledgeBasesByIDsCalls)++
	}
	selected := stringSet(knowledgeBaseIDs)
	result := make([]kb.KnowledgeBase, 0, len(knowledgeBaseIDs))
	for _, base := range store.bases {
		if base.WorkspaceID == workspaceID {
			if _, ok := selected[base.ID]; ok {
				result = append(result, base)
			}
		}
	}
	return result, nil
}

func (store fakeKnowledgeRootStore) GetKnowledgeBase(_ context.Context, workspaceID, id string) (kb.KnowledgeBase, error) {
	for _, base := range store.bases {
		if base.WorkspaceID == workspaceID && base.ID == id {
			return base, nil
		}
	}
	return kb.KnowledgeBase{}, gorm.ErrRecordNotFound
}

func (store fakeKnowledgeRootStore) ListKnowledgeBaseGrantsForSubject(_ context.Context, _ string, subjectType, subjectID string, kbIDs []string) ([]kb.KnowledgeBaseGrant, error) {
	selected := stringSet(kbIDs)
	result := make([]kb.KnowledgeBaseGrant, 0)
	for _, grant := range store.grants {
		if grant.SubjectType == subjectType && grant.SubjectID == subjectID {
			if _, ok := selected[grant.KnowledgeBaseID]; ok {
				result = append(result, grant)
			}
		}
	}
	return result, nil
}

func (store fakeKnowledgeRootStore) ListSourcesForKnowledgeBases(_ context.Context, _ string, kbIDs []string) ([]kb.Source, error) {
	if store.listSourcesForKnowledgeCalls != nil {
		(*store.listSourcesForKnowledgeCalls)++
	}
	selected := stringSet(kbIDs)
	result := make([]kb.Source, 0)
	for _, source := range store.sources {
		if _, ok := selected[source.KnowledgeBaseID]; ok {
			result = append(result, source)
		}
	}
	return result, nil
}

func (store fakeKnowledgeRootStore) ListSourcesByIDs(_ context.Context, workspaceID string, sourceIDs []string) ([]kb.Source, error) {
	if store.listSourcesByIDsCalls != nil {
		(*store.listSourcesByIDsCalls)++
	}
	selected := stringSet(sourceIDs)
	result := make([]kb.Source, 0, len(sourceIDs))
	for _, source := range store.sources {
		if source.WorkspaceID == workspaceID && source.DeletedAt == nil {
			if _, ok := selected[source.ID]; ok {
				result = append(result, source)
			}
		}
	}
	return result, nil
}

func (store fakeKnowledgeRootStore) GetSource(_ context.Context, workspaceID, kbID, sourceID string) (kb.Source, error) {
	for _, source := range store.sources {
		if source.WorkspaceID == workspaceID && source.KnowledgeBaseID == kbID && source.ID == sourceID && source.DeletedAt == nil {
			return source, nil
		}
	}
	return kb.Source{}, gorm.ErrRecordNotFound
}

func (store fakeKnowledgeRootStore) ListCurrentSourceRevisions(_ context.Context, workspaceID string, sourceIDs []string) ([]kb.SourceRevision, error) {
	if store.listSourceRevisionsCalls != nil {
		(*store.listSourceRevisionsCalls)++
	}
	selected := stringSet(sourceIDs)
	result := make([]kb.SourceRevision, 0, len(sourceIDs))
	for sourceID, revision := range store.revisions {
		if _, ok := selected[sourceID]; !ok {
			continue
		}
		if revision.SourceID == "" {
			revision.SourceID = sourceID
		}
		if revision.WorkspaceID == "" {
			revision.WorkspaceID = workspaceID
		}
		if revision.KnowledgeBaseID == "" {
			for _, source := range store.sources {
				if source.ID == sourceID {
					revision.KnowledgeBaseID = source.KnowledgeBaseID
					break
				}
			}
		}
		result = append(result, revision)
	}
	return result, nil
}

func (store fakeKnowledgeRootStore) ListSourceMirrorsBySourceIDs(_ context.Context, workspaceID string, sourceIDs []string) ([]kb.SourceMirror, error) {
	if store.listSourceMirrorsCalls != nil {
		(*store.listSourceMirrorsCalls)++
	}
	selected := stringSet(sourceIDs)
	result := make([]kb.SourceMirror, 0, len(sourceIDs))
	for sourceID, mirror := range store.mirrors {
		if _, ok := selected[sourceID]; !ok {
			continue
		}
		if mirror.SourceID == "" {
			mirror.SourceID = sourceID
		}
		if mirror.WorkspaceID == "" {
			mirror.WorkspaceID = workspaceID
		}
		if mirror.KnowledgeBaseID == "" {
			for _, source := range store.sources {
				if source.ID == sourceID {
					mirror.KnowledgeBaseID = source.KnowledgeBaseID
					break
				}
			}
		}
		result = append(result, mirror)
	}
	return result, nil
}

type fakeKnowledgeRootRepositoryStore struct {
	repositories []repos.ResourceRepository
	access       []repos.ResourceRepositoryAccessGrant
}

type fakeKnowledgeContentAuthority struct {
	rows map[string]content.Authority
}

func (authority fakeKnowledgeContentAuthority) GetAuthority(_ context.Context, workspaceID, domain, bindingKey string) (content.Authority, bool, error) {
	row, ok := authority.rows[bindingKey]
	if !ok {
		return content.Authority{WorkspaceID: workspaceID, Domain: domain, BindingKey: bindingKey, State: content.AuthorityStateLegacyActive}, false, nil
	}
	return row, true, nil
}

func (authority fakeKnowledgeContentAuthority) ListAuthoritiesForBindings(_ context.Context, _, _ string, bindingKeys []string) (map[string]content.Authority, error) {
	rows := make(map[string]content.Authority)
	for _, bindingKey := range bindingKeys {
		if row, ok := authority.rows[bindingKey]; ok {
			rows[bindingKey] = row
		}
	}
	return rows, nil
}

func (store fakeKnowledgeRootRepositoryStore) ListForResourceBatch(_ context.Context, _, _ string, resourceIDs []string) ([]repos.ResourceRepository, error) {
	selected := stringSet(resourceIDs)
	result := make([]repos.ResourceRepository, 0)
	for _, repository := range store.repositories {
		if _, ok := selected[repository.ResourceID]; ok {
			result = append(result, repository)
		}
	}
	return result, nil
}

func (store fakeKnowledgeRootRepositoryStore) ListAccessGrantsByIntentIDs(_ context.Context, _, _ string, intentIDs []string) ([]repos.ResourceRepositoryAccessGrant, error) {
	selected := stringSet(intentIDs)
	result := make([]repos.ResourceRepositoryAccessGrant, 0)
	for _, access := range store.access {
		if _, ok := selected[access.IntentID]; ok {
			result = append(result, access)
		}
	}
	return result, nil
}

func (store fakeKnowledgeRootRepositoryStore) ListActiveAccessGrantsForRepositorySubject(
	_ context.Context,
	workspaceID, repositoryFullName, subjectType, subjectID string,
) ([]repos.ResourceRepositoryAccessGrant, error) {
	result := make([]repos.ResourceRepositoryAccessGrant, 0)
	for _, access := range store.access {
		if access.WorkspaceID == workspaceID && access.RepoFullName == repositoryFullName &&
			access.SubjectType == subjectType && access.SubjectID == subjectID &&
			strings.TrimSpace(access.Status) != repos.AccessStatusRevoked {
			result = append(result, access)
		}
	}
	return result, nil
}

type fakeLexicons struct {
	roots []ReadyLexiconRoot
}

func (source fakeLexicons) ListReadyLexiconRoots(_ context.Context, _ string, kbIDs []string) ([]ReadyLexiconRoot, error) {
	selected := stringSet(kbIDs)
	result := make([]ReadyLexiconRoot, 0)
	for _, root := range source.roots {
		if _, ok := selected[root.KnowledgeBaseID]; ok {
			result = append(result, root)
		}
	}
	return result, nil
}

func TestCatalogExpandsOnlyAuthorizedReadyRootsInLayerOrder(t *testing.T) {
	now := time.Now().UTC()
	knowledge := fakeKnowledgeRootStore{
		bases: []kb.KnowledgeBase{
			{ID: "kb_a", WorkspaceID: "wsp_1", IsActive: true},
			{ID: "kb_b", WorkspaceID: "wsp_1", IsActive: true, DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read"},
			{ID: "kb_draft", WorkspaceID: "wsp_1", IsActive: true, PublicationState: "draft", DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read"},
			{ID: "kb_denied", WorkspaceID: "wsp_1", IsActive: true},
		},
		grants: []kb.KnowledgeBaseGrant{
			{ID: "grant_a", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_a", SubjectType: "user", SubjectID: "usr_1", Role: "view", RepositoryAccessProfile: "read"},
		},
		sources: []kb.Source{
			{ID: "src_a", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_a", FreshnessStatus: "current"},
			{ID: "src_b", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_b", FreshnessStatus: "stale"},
			{ID: "src_draft", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_draft", FreshnessStatus: "current"},
			{ID: "src_denied", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_denied"},
		},
		revisions: map[string]kb.SourceRevision{
			"src_a": {
				SourceCommitSHA:       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
				PublishedWikiRevision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
				FreshnessStatus:       "current",
			},
		},
		mirrors: map[string]kb.SourceMirror{
			"src_b": {
				LastMirroredCommit: "dddddddddddddddddddddddddddddddddddddddd",
				LastSuccessAt:      &now,
				SyncStatus:         kb.SourceMirrorSyncStatusSuccess,
			},
			"src_draft": {
				LastMirroredCommit: "ffffffffffffffffffffffffffffffffffffffff",
				LastSuccessAt:      &now,
				SyncStatus:         kb.SourceMirrorSyncStatusSuccess,
			},
		},
	}
	repositories := fakeKnowledgeRootRepositoryStore{
		repositories: []repos.ResourceRepository{
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_a", RepoRole: repos.RepoRolePrimary, RepoFullName: "wsp_1/source-a"},
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_a", RepoRole: repos.RepoRoleInsights, RepoFullName: "wsp_1/source-a.kb"},
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_b", RepoRole: repos.RepoRoleMirror, RepoFullName: "wsp_1/source-b"},
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_draft", RepoRole: repos.RepoRoleMirror, RepoFullName: "wsp_1/source-draft"},
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_denied", RepoRole: repos.RepoRolePrimary, RepoFullName: "wsp_1/denied"},
		},
		access: []repos.ResourceRepositoryAccessGrant{
			{IntentID: "grant_a", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_a", RepoRole: repos.RepoRolePrimary, SubjectType: "user", SubjectID: "usr_1", Materialized: true, Status: repos.AccessStatusCurrent},
			{IntentID: "grant_a", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_a", RepoRole: repos.RepoRoleInsights, SubjectType: "user", SubjectID: "usr_1", Materialized: true, Status: repos.AccessStatusCurrent},
		},
	}
	catalog := Catalog{
		Knowledge:       knowledge,
		Repositories:    repositories,
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
		Lexicons: fakeLexicons{roots: []ReadyLexiconRoot{
			{KnowledgeBaseID: "kb_a", RepositoryFullName: "wsp_1/lexicon", Revision: "cccccccccccccccccccccccccccccccccccccccc", FreshnessStatus: "current"},
			{KnowledgeBaseID: "kb_denied", RepositoryFullName: "wsp_1/denied-lexicon", Revision: "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"},
		}},
	}
	roots, err := catalog.ResolveAuthorizedRoots(context.Background(), ScopeRequest{Principal: protocol.Principal{
		OrganizationID: "org_1",
		WorkspaceID:    "wsp_1",
		RequesterID:    "usr_1",
		TurnID:         "turn_1",
	}})
	require.NoError(t, err)
	require.Len(t, roots, 4)
	require.Equal(t, []string{RootKindLexicon, RootKindInsights, RootKindPrimary, RootKindPrimary}, []string{
		roots[0].RootKind, roots[1].RootKind, roots[2].RootKind, roots[3].RootKind,
	})
	require.Equal(t, "kb_a", roots[0].KnowledgeBaseID)
	require.Empty(t, roots[0].SourceID)
	require.Equal(t, "ags-wiki:wsp_1/lexicon", roots[0].RepositoryRef)
	require.Equal(t, "ags-wiki:wsp_1/source-a.kb", roots[1].RepositoryRef)
	require.Equal(t, "ags-repo:wsp_1/source-a", roots[2].RepositoryRef)
	require.Equal(t, "src_b", roots[3].SourceID)
	require.Equal(t, "dddddddddddddddddddddddddddddddddddddddd", roots[3].Revision)
	require.NotContains(t, []string{roots[0].KnowledgeBaseID, roots[1].KnowledgeBaseID, roots[2].KnowledgeBaseID, roots[3].KnowledgeBaseID}, "kb_denied")
	require.NotContains(t, []string{roots[0].KnowledgeBaseID, roots[1].KnowledgeBaseID, roots[2].KnowledgeBaseID, roots[3].KnowledgeBaseID}, "kb_draft")
}

func TestCatalogRoutesNativeSourceAsOneExactContentVersionWithoutAGSRoots(t *testing.T) {
	now := time.Now().UTC()
	verifiedAt := now.Add(-time.Minute)
	knowledge := fakeKnowledgeRootStore{
		bases: []kb.KnowledgeBase{{
			ID: "kb_native", WorkspaceID: "wsp_1", IsActive: true,
			DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read",
		}},
		sources: []kb.Source{{ID: "src_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", Name: "Native source"}},
		revisions: map[string]kb.SourceRevision{"src_native": {
			ID: "rev_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", SourceID: "src_native",
			SourceContentID: "ctn_native", SourceContentVersionID: "ctv_native", SourceContentVerifiedAt: &verifiedAt,
		}},
		mappings: map[string]kb.SourceContentMapping{"rev_native": {
			ID: "map_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", SourceID: "src_native", SourceRevisionID: "rev_native",
			RepositoryRole: repos.RepoRolePrimary, ContentID: "ctn_native", ContentVersionID: "ctv_native",
			SearchProjectionDigest: strings.Repeat("a", 64), SearchProjectedAt: &verifiedAt, VerifiedAt: &verifiedAt,
		}},
	}
	catalog := Catalog{
		Knowledge: knowledge,
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_native", RepoRole: repos.RepoRolePrimary, RepoFullName: "legacy/source"},
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_native", RepoRole: repos.RepoRoleInsights, RepoFullName: "legacy/source.kb"},
		}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
		ContentAuthority: fakeKnowledgeContentAuthority{rows: map[string]content.Authority{
			"src_native": {State: content.AuthorityStateNativeActive},
		}},
	}
	resolution, err := catalog.ResolveAuthorizedScope(context.Background(), ScopeRequest{Principal: protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "turn_1",
	}, KnowledgeBaseIDs: []string{"kb_native"}, SourceIDs: []string{"src_native"}})
	require.NoError(t, err)
	require.Len(t, resolution.Roots, 1)
	require.Equal(t, RootKindPrimary, resolution.Roots[0].RootKind)
	require.Equal(t, "ctv_native", resolution.Roots[0].Revision)
	require.True(t, strings.HasPrefix(resolution.Roots[0].RepositoryRef, contentStoreRepositoryRefPrefix))
	require.NotContains(t, resolution.Roots[0].RepositoryRef, "legacy/source")
	require.Zero(t, resolution.Diagnostics.UnavailableSourceCount)
	require.Zero(t, resolution.Diagnostics.PartiallyAvailableSourceCount)
}

func TestCatalogNativeSourceFailsClosedAfterExactRepositoryRoleOverrideRevocation(t *testing.T) {
	verifiedAt := time.Now().UTC()
	knowledge := fakeKnowledgeRootStore{
		bases: []kb.KnowledgeBase{{ID: "kb_native", WorkspaceID: "wsp_1", IsActive: true}},
		grants: []kb.KnowledgeBaseGrant{{
			ID: "grant_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native",
			SubjectType: "user", SubjectID: "usr_1", Role: "view", RepositoryAccessProfile: "read",
		}},
		sources: []kb.Source{{ID: "src_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native"}},
		revisions: map[string]kb.SourceRevision{"src_native": {
			ID: "rev_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", SourceID: "src_native",
			SourceContentID: "ctn_native", SourceContentVersionID: "ctv_native", SourceContentVerifiedAt: &verifiedAt,
		}},
		mappings: map[string]kb.SourceContentMapping{"rev_native": {
			ID: "map_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", SourceID: "src_native", SourceRevisionID: "rev_native",
			RepositoryRole: repos.RepoRolePrimary, ContentID: "ctn_native", ContentVersionID: "ctv_native",
			SearchProjectionDigest: strings.Repeat("a", 64), SearchProjectedAt: &verifiedAt, VerifiedAt: &verifiedAt,
		}},
	}
	repositories := fakeKnowledgeRootRepositoryStore{access: []repos.ResourceRepositoryAccessGrant{{
		IntentID: "grant_native", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_native",
		RepoRole: repos.RepoRolePrimary, SubjectType: "user", SubjectID: "usr_1",
		Materialized: true, Status: repos.AccessStatusCurrent,
	}}}
	catalog := Catalog{
		Knowledge: knowledge, Repositories: repositories, WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
		ContentAuthority: fakeKnowledgeContentAuthority{rows: map[string]content.Authority{
			"src_native": {State: content.AuthorityStateNativeActive},
		}},
	}
	request := ScopeRequest{Principal: protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "turn_1",
	}, KnowledgeBaseIDs: []string{"kb_native"}, SourceIDs: []string{"src_native"}}

	resolution, err := catalog.ResolveAuthorizedScope(context.Background(), request)
	require.NoError(t, err)
	require.Len(t, resolution.Roots, 1)

	knowledge.overrides = []kb.KnowledgeBaseSourceRepositoryAccessOverride{{
		WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", GrantID: "grant_native", SourceID: "src_native",
		RepoRole: repos.RepoRolePrimary, SubjectType: "user", SubjectID: "usr_1", RepositoryAccessProfile: kb.KnowledgeBaseRepositoryAccessProfileNone,
	}}
	catalog.Knowledge = knowledge
	catalog.Repositories = fakeKnowledgeRootRepositoryStore{} // stale projection cannot keep native access alive
	resolution, err = catalog.ResolveAuthorizedScope(context.Background(), request)
	require.NoError(t, err)
	require.Empty(t, resolution.Roots)
	require.Zero(t, resolution.Diagnostics.AuthorizedSourceCount)
}

func TestCatalogReplaysNativeCitationByExactHistoricalContentVersion(t *testing.T) {
	verifiedAt := time.Now().UTC()
	knowledge := fakeKnowledgeRootStore{
		bases: []kb.KnowledgeBase{{
			ID: "kb_native", WorkspaceID: "wsp_1", IsActive: true,
			DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read",
		}},
		sources: []kb.Source{{ID: "src_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", Name: "Native source"}},
		mappings: map[string]kb.SourceContentMapping{"rev_old": {
			ID: "map_old", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", SourceID: "src_native", SourceRevisionID: "rev_old",
			RepositoryRole: repos.RepoRolePrimary, ContentID: "ctn_native", ContentVersionID: "ctv_old", VerifiedAt: &verifiedAt,
		}},
	}
	catalog := Catalog{
		Knowledge: knowledge, Repositories: fakeKnowledgeRootRepositoryStore{}, WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
		ContentAuthority: fakeKnowledgeContentAuthority{rows: map[string]content.Authority{
			"src_native": {State: content.AuthorityStateNativeActive},
		}},
	}
	root, status, mode, err := catalog.ResolveCitationRoot(context.Background(), protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "turn_1",
	}, CitationMetadata{
		KnowledgeBaseID: "kb_native", SourceID: "src_native", RootKind: RootKindPrimary,
		RepoRole: repos.RepoRolePrimary, Revision: "ctv_old",
	})
	require.NoError(t, err)
	require.Equal(t, CitationStatusAvailable, status)
	require.Equal(t, CitationOpenModeSource, mode)
	require.Equal(t, "ctv_old", root.Revision)
	require.True(t, strings.HasPrefix(root.RepositoryRef, contentStoreRepositoryRefPrefix))

	_, status, _, err = catalog.ResolveCitationRoot(context.Background(), protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "turn_1",
	}, CitationMetadata{
		KnowledgeBaseID: "kb_native", SourceID: "src_native", RootKind: RootKindInsights,
		RepoRole: repos.RepoRoleInsights, Revision: strings.Repeat("a", 40),
	})
	require.NoError(t, err)
	require.Equal(t, CitationStatusRevisionUnavailable, status, "native authority must not fall back to an AGS insights citation")
}

func TestCatalogNativeCitationFailsClosedAfterExactRepositoryRoleOverrideRevocation(t *testing.T) {
	verifiedAt := time.Now().UTC()
	knowledge := fakeKnowledgeRootStore{
		bases: []kb.KnowledgeBase{{ID: "kb_native", WorkspaceID: "wsp_1", IsActive: true}},
		grants: []kb.KnowledgeBaseGrant{{
			ID: "grant_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native",
			SubjectType: "user", SubjectID: "usr_1", Role: "view", RepositoryAccessProfile: "read",
		}},
		sources: []kb.Source{{ID: "src_native", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native"}},
		mappings: map[string]kb.SourceContentMapping{"rev_old": {
			ID: "map_old", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", SourceID: "src_native", SourceRevisionID: "rev_old",
			RepositoryRole: repos.RepoRolePrimary, ContentID: "ctn_native", ContentVersionID: "ctv_old", VerifiedAt: &verifiedAt,
		}},
	}
	repositories := fakeKnowledgeRootRepositoryStore{access: []repos.ResourceRepositoryAccessGrant{{
		IntentID: "grant_native", WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_native",
		RepoRole: repos.RepoRolePrimary, SubjectType: "user", SubjectID: "usr_1",
		Materialized: true, Status: repos.AccessStatusCurrent,
	}}}
	catalog := Catalog{
		Knowledge: knowledge, Repositories: repositories, WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
		ContentAuthority: fakeKnowledgeContentAuthority{rows: map[string]content.Authority{
			"src_native": {State: content.AuthorityStateNativeActive},
		}},
	}
	principal := protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "turn_1",
	}
	citation := CitationMetadata{
		KnowledgeBaseID: "kb_native", SourceID: "src_native", RootKind: RootKindPrimary,
		RepoRole: repos.RepoRolePrimary, Revision: "ctv_old",
	}

	_, status, mode, err := catalog.ResolveCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusAvailable, status)
	require.Equal(t, CitationOpenModeSource, mode)

	knowledge.overrides = []kb.KnowledgeBaseSourceRepositoryAccessOverride{{
		WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_native", GrantID: "grant_native", SourceID: "src_native",
		RepoRole: repos.RepoRolePrimary, SubjectType: "user", SubjectID: "usr_1", RepositoryAccessProfile: kb.KnowledgeBaseRepositoryAccessProfileNone,
	}}
	catalog.Knowledge = knowledge
	catalog.Repositories = fakeKnowledgeRootRepositoryStore{} // stale projection cannot keep native citation access alive
	_, status, mode, err = catalog.ResolveCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusForbidden, status)
	require.Empty(t, mode)
}

func TestCatalogReportsOnlyAuthorizedIncompleteReadyRootCoverage(t *testing.T) {
	catalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases: []kb.KnowledgeBase{
				{
					ID: "kb_allowed", WorkspaceID: "wsp_1", IsActive: true,
					DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read",
				},
				{ID: "kb_denied", WorkspaceID: "wsp_1", IsActive: true},
			},
			sources: []kb.Source{
				{ID: "src_partial", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_allowed"},
				{ID: "src_unavailable", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_allowed"},
				{ID: "src_denied", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_denied"},
			},
			revisions: map[string]kb.SourceRevision{
				"src_partial": {
					SourceCommitSHA: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
				},
				"src_denied": {
					SourceCommitSHA: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
				},
			},
			mirrors: map[string]kb.SourceMirror{},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{
			repositories: []repos.ResourceRepository{
				{
					WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
					ResourceID: "src_partial", RepoRole: repos.RepoRolePrimary,
					RepoFullName: "wsp_1/partial",
				},
				{
					WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
					ResourceID: "src_partial", RepoRole: repos.RepoRoleInsights,
					RepoFullName: "wsp_1/partial.kb",
				},
				{
					WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
					ResourceID: "src_unavailable", RepoRole: repos.RepoRolePrimary,
					RepoFullName: "wsp_1/unavailable",
				},
				{
					WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
					ResourceID: "src_denied", RepoRole: repos.RepoRolePrimary,
					RepoFullName: "wsp_1/denied",
				},
			},
		},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}

	resolution, err := catalog.ResolveAuthorizedScope(context.Background(), ScopeRequest{
		Principal: protocol.Principal{
			OrganizationID: "org_1", WorkspaceID: "wsp_1",
			RequesterID: "usr_1", TurnID: "turn_1",
		},
	})
	require.NoError(t, err)
	require.Len(t, resolution.Roots, 1)
	require.Equal(t, "src_partial", resolution.Roots[0].SourceID)
	require.Equal(t, 1, resolution.Diagnostics.AuthorizedKnowledgeBaseCount)
	require.Equal(t, 2, resolution.Diagnostics.AuthorizedSourceCount)
	require.Zero(t, resolution.Diagnostics.UnavailableKnowledgeBaseCount)
	require.Equal(t, 1, resolution.Diagnostics.UnavailableSourceCount)
	require.Equal(t, 1, resolution.Diagnostics.PartiallyAvailableSourceCount)
}

func TestCatalogRequestedScopeOnlyShrinksAndNeverDisclosesDeniedIDs(t *testing.T) {
	catalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases: []kb.KnowledgeBase{
				{ID: "kb_allowed", WorkspaceID: "wsp_1", IsActive: true, DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read"},
				{ID: "kb_denied", WorkspaceID: "wsp_1", IsActive: true},
			},
			sources: []kb.Source{
				{ID: "src_allowed", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_allowed"},
				{ID: "src_denied", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_denied"},
			},
			revisions: map[string]kb.SourceRevision{
				"src_allowed": {SourceCommitSHA: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
			},
			mirrors: map[string]kb.SourceMirror{},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_allowed", RepoRole: repos.RepoRolePrimary, RepoFullName: "wsp_1/allowed"},
		}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}
	principal := protocol.Principal{OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "turn_1"}

	roots, err := catalog.ResolveAuthorizedRoots(context.Background(), ScopeRequest{
		Principal: principal, KnowledgeBaseIDs: []string{"kb_allowed"}, SourceIDs: []string{"src_allowed"},
	})
	require.NoError(t, err)
	require.Len(t, roots, 1)
	require.Equal(t, "src_allowed", roots[0].SourceID)

	roots, err = catalog.ResolveAuthorizedRoots(context.Background(), ScopeRequest{
		Principal: principal, KnowledgeBaseIDs: []string{"kb_denied"}, SourceIDs: []string{"src_denied"},
	})
	require.NoError(t, err)
	require.Empty(t, roots)
}

func TestCatalogSelectedSourceUsesOnlyRequestBoundedBatchLoads(t *testing.T) {
	var listAllBases, listBasesByID, listAllKBSources, listSourcesByID, listRevisions, listMirrors int
	knowledge := fakeKnowledgeRootStore{
		bases: []kb.KnowledgeBase{
			{ID: "kb_target", WorkspaceID: "wsp_1", IsActive: true, DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read"},
			{ID: "kb_unrelated", WorkspaceID: "wsp_1", IsActive: true, DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read"},
		},
		sources: []kb.Source{
			{ID: "src_target", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_target"},
			{ID: "src_target_2", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_target"},
			{ID: "src_unrelated", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_unrelated"},
		},
		revisions: map[string]kb.SourceRevision{
			"src_target":   {SourceCommitSHA: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
			"src_target_2": {SourceCommitSHA: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},
		},
		mirrors:                      map[string]kb.SourceMirror{},
		listKnowledgeBasesCalls:      &listAllBases,
		listKnowledgeBasesByIDsCalls: &listBasesByID,
		listSourcesForKnowledgeCalls: &listAllKBSources,
		listSourcesByIDsCalls:        &listSourcesByID,
		listSourceRevisionsCalls:     &listRevisions,
		listSourceMirrorsCalls:       &listMirrors,
	}
	catalog := Catalog{
		Knowledge: knowledge,
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{
			{
				WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
				ResourceID: "src_target", RepoRole: repos.RepoRolePrimary,
				RepoFullName: "wsp_1/target",
			},
			{
				WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
				ResourceID: "src_target_2", RepoRole: repos.RepoRolePrimary,
				RepoFullName: "wsp_1/target-2",
			},
		}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}

	resolution, err := catalog.ResolveAuthorizedScope(context.Background(), ScopeRequest{
		Principal: protocol.Principal{OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "turn_1"},
		SourceIDs: []string{"src_target", "src_target_2"},
	})
	require.NoError(t, err)
	require.Len(t, resolution.Roots, 2)
	require.Equal(t, "src_target", resolution.Roots[0].SourceID)
	require.Zero(t, listAllBases, "explicit source scope must not page unrelated workspace KBs")
	require.Equal(t, 1, listBasesByID)
	require.Zero(t, listAllKBSources, "explicit source scope must not hydrate sibling sources")
	require.Equal(t, 1, listSourcesByID)
	require.Equal(t, 1, listRevisions, "current revisions must be loaded in one bounded query")
	require.Equal(t, 1, listMirrors, "mirrors must be loaded in one bounded query")
}

func TestCatalogExplicitDenyOverridesWorkspaceDefaultAccess(t *testing.T) {
	catalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases: []kb.KnowledgeBase{{
				ID:                                  "kb_default",
				WorkspaceID:                         "wsp_1",
				IsActive:                            true,
				DefaultWorkspaceMemberRole:          "view",
				DefaultRepositoryAccessProfile:      "read",
				AllowKnowledgeQAWithoutSourceAccess: true,
			}},
			grants: []kb.KnowledgeBaseGrant{{
				ID:                      "grant_denied",
				WorkspaceID:             "wsp_1",
				KnowledgeBaseID:         "kb_default",
				SubjectType:             "user",
				SubjectID:               "usr_1",
				Role:                    "none",
				RepositoryAccessProfile: "none",
			}},
			sources: []kb.Source{{
				ID: "src_private", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_default",
			}},
			revisions: map[string]kb.SourceRevision{
				"src_private": {SourceCommitSHA: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
			},
			mirrors: map[string]kb.SourceMirror{},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{{
			WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
			ResourceID: "src_private", RepoRole: repos.RepoRolePrimary,
			RepoFullName: "wsp_1/private",
		}}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}
	principal := protocol.Principal{
		OrganizationID: "org_1",
		WorkspaceID:    "wsp_1",
		RequesterID:    "usr_1",
		TurnID:         "turn_1",
	}

	roots, err := catalog.ResolveAuthorizedRoots(context.Background(), ScopeRequest{
		Principal: principal, KnowledgeBaseIDs: []string{"kb_default"},
	})
	require.NoError(t, err)
	require.Empty(t, roots)

	_, status, _, err := catalog.ResolveCitationRoot(context.Background(), principal, CitationMetadata{
		KnowledgeBaseID: "kb_default",
		SourceID:        "src_private",
		RootKind:        RootKindPrimary,
		RepoRole:        repos.RepoRolePrimary,
		Revision:        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
	})
	require.NoError(t, err)
	require.Equal(t, CitationStatusForbidden, status)
}

func TestCatalogRejectsRepositoryAccessIntentForAnotherResourceType(t *testing.T) {
	base := kb.KnowledgeBase{ID: "kb_1", WorkspaceID: "wsp_1", IsActive: true}
	knowledge := fakeKnowledgeRootStore{
		bases: []kb.KnowledgeBase{base},
		grants: []kb.KnowledgeBaseGrant{{
			ID: "grant_1", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_1",
			SubjectType: "user", SubjectID: "usr_1", Role: "view",
			RepositoryAccessProfile: "read",
		}},
		sources: []kb.Source{{
			ID: "shared_resource_id", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_1",
		}},
		revisions: map[string]kb.SourceRevision{
			"shared_resource_id": {SourceCommitSHA: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
		},
		mirrors: map[string]kb.SourceMirror{},
	}
	repositories := fakeKnowledgeRootRepositoryStore{
		repositories: []repos.ResourceRepository{{
			WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
			ResourceID: "shared_resource_id", RepoRole: repos.RepoRolePrimary,
			RepoFullName: "wsp_1/private-source",
		}},
		access: []repos.ResourceRepositoryAccessGrant{{
			IntentID: "grant_1", ResourceType: repos.ResourceTypeMemory,
			ResourceID: "shared_resource_id", RepoRole: repos.RepoRolePrimary,
			SubjectType: "user", SubjectID: "usr_1", Materialized: true,
			Status: repos.AccessStatusCurrent,
		}},
	}
	catalog := Catalog{
		Knowledge: knowledge, Repositories: repositories,
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}
	principal := protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1",
		RequesterID: "usr_1", TurnID: "turn_1",
	}

	roots, err := catalog.ResolveAuthorizedRoots(context.Background(), ScopeRequest{
		Principal: principal, KnowledgeBaseIDs: []string{"kb_1"},
	})
	require.NoError(t, err)
	require.Empty(t, roots)

	_, status, _, err := catalog.ResolveCitationRoot(context.Background(), principal, CitationMetadata{
		KnowledgeBaseID: "kb_1", SourceID: "shared_resource_id",
		RootKind: RootKindPrimary, RepoRole: repos.RepoRolePrimary,
		Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
	})
	require.NoError(t, err)
	require.Equal(t, CitationStatusForbidden, status)
}

func TestCatalogSourceOnlyScopeExcludesUnselectedKnowledgeBaseLexicons(t *testing.T) {
	catalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases: []kb.KnowledgeBase{
				{ID: "kb_a", WorkspaceID: "wsp_1", IsActive: true, DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read"},
				{ID: "kb_b", WorkspaceID: "wsp_1", IsActive: true, DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read"},
			},
			sources: []kb.Source{
				{ID: "src_a", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_a"},
				{ID: "src_b", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_b"},
			},
			revisions: map[string]kb.SourceRevision{
				"src_a": {SourceCommitSHA: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
				"src_b": {SourceCommitSHA: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},
			},
			mirrors: map[string]kb.SourceMirror{},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_a", RepoRole: repos.RepoRolePrimary, RepoFullName: "wsp_1/source-a"},
			{WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource, ResourceID: "src_b", RepoRole: repos.RepoRolePrimary, RepoFullName: "wsp_1/source-b"},
		}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
		Lexicons: fakeLexicons{roots: []ReadyLexiconRoot{
			{KnowledgeBaseID: "kb_a", RepositoryFullName: "wsp_1/lexicon-a", Revision: "cccccccccccccccccccccccccccccccccccccccc"},
			{KnowledgeBaseID: "kb_b", RepositoryFullName: "wsp_1/lexicon-b", Revision: "dddddddddddddddddddddddddddddddddddddddd"},
		}},
	}

	roots, err := catalog.ResolveAuthorizedRoots(context.Background(), ScopeRequest{
		Principal: protocol.Principal{
			OrganizationID: "org_1",
			WorkspaceID:    "wsp_1",
			RequesterID:    "usr_1",
			TurnID:         "turn_1",
		},
		SourceIDs: []string{"src_a"},
	})
	require.NoError(t, err)
	require.Len(t, roots, 1)
	require.Equal(t, "src_a", roots[0].SourceID)
	require.Equal(t, RootKindPrimary, roots[0].RootKind)
}

func TestCatalogFailsClosedWithoutCurrentWorkspaceMembership(t *testing.T) {
	catalog := Catalog{
		Knowledge:       fakeKnowledgeRootStore{},
		Repositories:    fakeKnowledgeRootRepositoryStore{},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: false},
	}
	roots, err := catalog.ResolveAuthorizedRoots(context.Background(), ScopeRequest{Principal: protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "turn_1",
	}})
	require.NoError(t, err)
	require.Empty(t, roots)
}

func TestCatalogPagesEveryKnowledgeBaseBeforeApplyingScope(t *testing.T) {
	bases := make([]kb.KnowledgeBase, knowledgeRootCatalogPageSize+1)
	for index := range bases {
		bases[index] = kb.KnowledgeBase{
			ID: "kb_other", WorkspaceID: "wsp_1", IsActive: true,
			DefaultWorkspaceMemberRole:     "view",
			DefaultRepositoryAccessProfile: "read",
		}
	}
	last := &bases[len(bases)-1]
	last.ID = "kb_last_page"
	source := kb.Source{
		ID: "src_last_page", WorkspaceID: "wsp_1",
		KnowledgeBaseID: last.ID,
	}
	catalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases: bases, sources: []kb.Source{source},
			revisions: map[string]kb.SourceRevision{
				source.ID: {SourceCommitSHA: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
			},
			mirrors: map[string]kb.SourceMirror{},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{{
			WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
			ResourceID: source.ID, RepoRole: repos.RepoRolePrimary,
			RepoFullName: "wsp_1/last-page",
		}}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}

	roots, err := catalog.ResolveAuthorizedRoots(context.Background(), ScopeRequest{
		Principal: protocol.Principal{
			OrganizationID: "org_1", WorkspaceID: "wsp_1",
			RequesterID: "usr_1", TurnID: "turn_1",
		},
	})
	require.NoError(t, err)
	require.Len(t, roots, 1)
	require.Equal(t, source.ID, roots[0].SourceID)
}

func TestCatalogCitationResolutionDistinguishesDeletedForbiddenAndUnavailable(t *testing.T) {
	principal := protocol.Principal{OrganizationID: "org_1", WorkspaceID: "wsp_1", RequesterID: "usr_1", TurnID: "citation-open"}
	base := kb.KnowledgeBase{
		ID: "kb_1", WorkspaceID: "wsp_1", IsActive: true,
		DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read",
	}
	citation := CitationMetadata{
		KnowledgeBaseID: "kb_1", SourceID: "src_1", RootKind: RootKindPrimary, RepoRole: RepoRolePrimary,
		Revision: "sha-historical",
	}

	deletedCatalog := Catalog{
		Knowledge:    fakeKnowledgeRootStore{bases: []kb.KnowledgeBase{base}},
		Repositories: fakeKnowledgeRootRepositoryStore{}, WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}
	_, status, _, err := deletedCatalog.ResolveCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusSourceDeleted, status)

	inactiveBase := base
	inactiveBase.IsActive = false
	inactiveCatalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases:   []kb.KnowledgeBase{inactiveBase},
			sources: []kb.Source{{ID: "src_1", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_1"}},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{}, WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}
	_, status, _, err = inactiveCatalog.ResolveCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusForbidden, status)

	deniedBase := base
	deniedBase.DefaultWorkspaceMemberRole = "none"
	deniedBase.DefaultRepositoryAccessProfile = "none"
	deniedCatalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases:     []kb.KnowledgeBase{deniedBase},
			sources:   []kb.Source{{ID: "src_1", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_1"}},
			revisions: map[string]kb.SourceRevision{"src_1": {SourceCommitSHA: "sha-current"}},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{}, WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}
	_, status, _, err = deniedCatalog.ResolveCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusForbidden, status)

	unavailableCatalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases:     []kb.KnowledgeBase{base},
			sources:   []kb.Source{{ID: "src_1", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_1"}},
			revisions: map[string]kb.SourceRevision{"src_1": {PublishedWikiRevision: "sha-insights"}},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{{
			WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
			ResourceID: "src_1", RepoRole: repos.RepoRoleInsights, RepoFullName: "wsp_1/source-1",
		}}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}
	_, status, _, err = unavailableCatalog.ResolveCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusRevisionUnavailable, status)

	historicalRevisionCatalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases:   []kb.KnowledgeBase{base},
			sources: []kb.Source{{ID: "src_1", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_1"}},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{{
			WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
			ResourceID: "src_1", RepoRole: repos.RepoRolePrimary, RepoFullName: "wsp_1/source-1",
		}}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
	}
	root, status, openMode, err := historicalRevisionCatalog.ResolveCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusAvailable, status)
	require.Equal(t, CitationOpenModeEvidence, openMode)
	require.Equal(t, "ags-repo:wsp_1/source-1", root.RepositoryRef)
	require.Equal(t, "sha-historical", root.Revision)
}

func TestCatalogCitationOpenUsesEvidenceModeForInheritedLexicon(t *testing.T) {
	principal := protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1",
		RequesterID: "usr_1", TurnID: "citation-open",
	}
	catalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{bases: []kb.KnowledgeBase{{
			ID: "kb_1", WorkspaceID: "wsp_1", IsActive: true,
			DefaultWorkspaceMemberRole: "view", DefaultRepositoryAccessProfile: "read",
		}}},
		Repositories:    fakeKnowledgeRootRepositoryStore{},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: true},
		Lexicons: fakeLexicons{roots: []ReadyLexiconRoot{{
			KnowledgeBaseID: "kb_1", RepositoryFullName: "wsp_1/kb-1-lexicon",
			Revision: "sha-current", FreshnessStatus: "ready",
		}}},
	}

	root, status, openMode, err := catalog.ResolveCitationRoot(context.Background(), principal, CitationMetadata{
		KnowledgeBaseID: "kb_1", RootKind: RootKindLexicon, RepoRole: RepoRoleWiki,
		Revision: "sha-historical", Path: "entries/payments.md", LineStart: 1, LineEnd: 8,
	})
	require.NoError(t, err)
	require.Equal(t, CitationStatusAvailable, status)
	require.Equal(t, CitationOpenModeEvidence, openMode)
	require.Equal(t, "ags-wiki:wsp_1/kb-1-lexicon", root.RepositoryRef)
}

func TestCatalogSharedCitationFallbackNeverGrantsRepositoryNavigation(t *testing.T) {
	principal := protocol.Principal{
		OrganizationID: "org_1", WorkspaceID: "wsp_1",
		RequesterID: "usr_recipient", TurnID: "kqt_shared",
	}
	citation := CitationMetadata{
		KnowledgeBaseID: "kb_1", SourceID: "src_1", RootKind: RootKindPrimary,
		RepoRole: RepoRolePrimary, Revision: "sha-historical",
	}
	catalog := Catalog{
		Knowledge: fakeKnowledgeRootStore{
			bases:   []kb.KnowledgeBase{{ID: "kb_1", WorkspaceID: "wsp_1", IsActive: true}},
			sources: []kb.Source{{ID: "src_1", WorkspaceID: "wsp_1", KnowledgeBaseID: "kb_1"}},
		},
		Repositories: fakeKnowledgeRootRepositoryStore{repositories: []repos.ResourceRepository{{
			WorkspaceID: "wsp_1", ResourceType: repos.ResourceTypeKBSource,
			ResourceID: "src_1", RepoRole: repos.RepoRolePrimary,
			RepoFullName: "wsp_1/source-1",
		}}},
		WorkspaceAccess: fakeWorkspaceAccess{allowed: false},
	}

	_, status, openMode, err := catalog.ResolveCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusForbidden, status)
	require.Empty(t, openMode)

	root, status, err := catalog.ResolveSharedCitationRoot(context.Background(), principal, citation)
	require.NoError(t, err)
	require.Equal(t, CitationStatusAvailable, status)
	require.Equal(t, "ags-repo:wsp_1/source-1", root.RepositoryRef)
	require.Equal(t, "sha-historical", root.Revision)
}
