/**
 * Centralized Query Keys for React Query
 *
 * This ensures consistent cache key management across the application
 * and prevents inline array declarations that are harder to maintain.
 */

import { ProjectLocator } from "@/sdk";

export const KEYS = {
  // Public config (no auth required)
  publicConfig: () => ["publicConfig"] as const,

  // Polled separately from publicConfig (which is cached forever) to detect
  // a deployed version newer than the client's own build.
  appVersionCheck: () => ["appVersionCheck"] as const,

  // Auth-related queries
  session: () => ["session"] as const,

  messages: (locator: string) => ["messages", locator] as const,

  // Organizations list
  organizations: () => ["organizations"] as const,

  // Organization members (scoped by org)
  members: (locator: ProjectLocator) => [locator, "members"] as const,

  // Organization invitations (scoped by org)
  invitations: (locator: ProjectLocator) => [locator, "invitations"] as const,

  // Organization roles (scoped by org)
  organizationRoles: (locator: ProjectLocator) =>
    [locator, "organization-roles"] as const,

  // Current user's resolved capability bitmap within the active org
  myCapabilities: (locator: ProjectLocator) =>
    [locator, "my-capabilities"] as const,

  // Task board items (scoped by org)
  taskBoardItems: (locator: ProjectLocator) =>
    [locator, "task-board-items"] as const,

  // A task's linked pull requests (live state fetched from GitHub)
  taskBoardItemPrs: (locator: ProjectLocator, itemId: string) =>
    [locator, "task-board-item-prs", itemId] as const,

  // A task's change timeline (created, status/assignee changes)
  taskBoardActivity: (locator: ProjectLocator, itemId: string) =>
    [locator, "task-board-activity", itemId] as const,

  // A task's comment threads
  taskBoardComments: (locator: ProjectLocator, itemId: string) =>
    [locator, "task-board-comments", itemId] as const,

  homeGithubRecentPrs: (orgId: string, connectionId: string) =>
    ["home-github-recent-prs", orgId, connectionId] as const,

  homeGithubContributions: (orgId: string, connectionId: string) =>
    ["home-github-contributions", orgId, connectionId] as const,

  // Authenticated report deck for a scanned domain (/report/:domain). `lang`
  // (the viewer's locale) is part of the key so switching language refetches.
  report: (domain: string, key?: string, lang?: string) =>
    ["report", domain, key ?? "", lang ?? ""] as const,
  // Prefix of `report` above (no key/lang) — invalidates every variant for a
  // domain at once, e.g. after an in-place login unlocks the full deck.
  reportAll: (domain: string) => ["report", domain] as const,

  commerceDiscoveryConnection: (orgId: string, connectionId: string) =>
    ["commerce-discovery", "connection", orgId, connectionId] as const,
  // Owner diagnostic (get_my_diagnostic) polled by the home report banner —
  // keyed per org + connection so a credential rotation forces a fresh fetch.
  commerceDiscoveryDiagnostic: (orgId: string, connectionId: string) =>
    ["commerce-discovery", "diagnostic", orgId, connectionId] as const,
  commerceDiscoveryVirtualMcp: (orgId: string, virtualMcpId: string) =>
    ["commerce-discovery", "virtual-mcp", orgId, virtualMcpId] as const,

  // Commerce companion discovery (Commerce Discovery's live config schema,
  // candidate connections satisfying a binding, and the registry batch).
  commerceDiscoveryCompanionSchema: (orgId: string, connectionId: string) =>
    ["commerce-discovery", "companion-schema", orgId, connectionId] as const,
  commerceDiscoveryCompanionConnections: (orgId: string, key: string) =>
    ["commerce-discovery", "companion-connections", orgId, key] as const,
  // Prefix for every companion-connections query in an org, regardless of the
  // requirements-signature `key`. Use with invalidateQueries to refetch all
  // variants after a connection is created/linked/updated.
  commerceDiscoveryCompanionConnectionsPrefix: (orgId: string) =>
    ["commerce-discovery", "companion-connections", orgId] as const,
  commerceDiscoveryCompanionRegistry: (orgId: string, key: string) =>
    ["commerce-discovery", "companion-registry", orgId, key] as const,
  commerceDiscoveryCompanionOAuthStatus: (
    orgId: string,
    connectionId: string,
  ) =>
    [
      "commerce-discovery",
      "companion-oauth-status",
      orgId,
      connectionId,
    ] as const,
  commerceDiscoveryCompanionGaProperties: (
    orgId: string,
    connectionId: string,
  ) =>
    [
      "commerce-discovery",
      "companion-ga-properties",
      orgId,
      connectionId,
    ] as const,
  commerceDiscoveryCompanionGscSites: (orgId: string, connectionId: string) =>
    ["commerce-discovery", "companion-gsc-sites", orgId, connectionId] as const,
  // GitHub repo picker: repos matching a server-side search (empty = default
  // page) for the companion connection. Keyed by query so each search term is
  // cached independently.
  commerceDiscoveryCompanionGithubRepos: (
    orgId: string,
    connectionId: string,
    query: string,
  ) =>
    [
      "commerce-discovery",
      "companion-github-repos",
      orgId,
      connectionId,
      query,
    ] as const,
  // The repo currently selected on the Commerce Discovery connection
  // (github_repo), read once for prefill — independent of the search query.
  commerceDiscoveryCompanionGithubSelected: (
    orgId: string,
    connectionId: string,
  ) =>
    [
      "commerce-discovery",
      "companion-github-selected",
      orgId,
      connectionId,
    ] as const,
  // Per-(org, siteUrl) connection status from commerce-discovery — the single
  // source of truth for "Conectado" across both lanes (OAuth + shared-SA).
  commerceDiscoveryConnectionStatus: (orgId: string, siteUrl: string) =>
    ["commerce-discovery", "connection-status", orgId, siteUrl] as const,

  connectionActivity: (
    connectionId: string,
    timeframe: string,
    orgId: string,
  ) => ["monitoring", "activity", connectionId, timeframe, orgId] as const,

  isMCPAuthenticated: (url: string, token: string | null) =>
    ["is-mcp-authenticated", url, token] as const,

  // MCP tools (scoped by URL and optional token)
  mcpTools: (url: string, token?: string | null) =>
    ["mcp", "tools", url, token] as const,

  // MCP client (scoped by orgId, connectionId, token, and Studio URL)
  mcpClient: (
    orgId: string,
    connectionId: string,
    token: string,
    studioUrl: string,
  ) => ["mcp", "client", orgId, connectionId, token, studioUrl] as const,

  // MCP client-based queries (scoped by client instance)
  mcpToolsList: (client: unknown) =>
    ["mcp", "client", client, "tools"] as const,
  mcpResourcesList: (client: unknown) =>
    ["mcp", "client", client, "resources"] as const,
  mcpPromptsList: (client: unknown) =>
    ["mcp", "client", client, "prompts"] as const,
  mcpReadResource: (client: unknown, uri: string) =>
    ["mcp", "client", client, "resource", uri] as const,
  mcpUiResourceHtml: (orgSlug: string, connectionId: string, uri: string) =>
    ["mcp", "ui-resource-html", orgSlug, connectionId, uri] as const,
  mcpGetPrompt: (client: unknown, name: string, argsKey: string) =>
    ["mcp", "client", client, "prompt", name, argsKey] as const,
  mcpToolCall: (client: unknown, toolName: string, argsKey: string) =>
    ["mcp", "client", client, "tool-call", toolName, argsKey] as const,

  // Prefix for all MCP-client queries (mcpClient, mcpToolsList,
  // mcpResourcesList, mcpPromptsList, mcpReadResource, mcpGetPrompt,
  // mcpToolCall — all start with ["mcp", "client", ...]). Use with
  // invalidateQueries to blow away every cached client query at once,
  // e.g. after an MCP connection re-authenticates.
  mcpClientPrefix: () => ["mcp", "client"] as const,

  // Most recent thread per agent.
  virtualMcpLastUsed: (orgId: string, ids: string[]) =>
    ["virtual-mcp", "last-used", orgId, ids] as const,

  githubBranches: (
    orgId: string,
    orgSlug: string,
    connectionId: string | null | undefined,
    owner: string,
    repo: string,
  ) => ["github-branches", orgId, orgSlug, connectionId, owner, repo] as const,

  organizationSettings: (organizationId: string) =>
    ["organization-settings", organizationId] as const,

  organizationTaskQuota: (organizationId: string) =>
    ["organization-task-quota", organizationId] as const,

  userModelPreferences: (organizationId: string) =>
    ["user-model-preferences", organizationId] as const,

  // API keys (scoped by organization; the LIST tool filters by org server-side)
  apiKeysList: (organizationId: string) =>
    ["api-keys", organizationId] as const,

  // Active organization
  activeOrganization: (org: string | undefined) =>
    ["activeOrganization", org] as const,

  // Org access status (for /:org gate — pending invite / auto-join / no access)
  orgAccessStatus: (slug: string) => ["org-access-status", slug] as const,

  // Models list (scoped by organization)
  modelsList: (orgId: string) => ["models-list", orgId] as const,

  // Home next-actions — agent prompts under Chat.Input.
  homeNextActions: (orgSlug: string) => ["home-next-actions", orgSlug] as const,

  // Home tile-board layout (positions/sizes/hidden), KV-backed per org.
  boardLayout: (orgSlug: string) => ["board-layout", orgSlug] as const,

  // Prompts exposed by an agent's gateway (drawer's prompt list).
  agentPrompts: (orgId: string, agentId: string) =>
    ["agent-prompts", orgId, agentId] as const,

  // Allowed models for current user (scoped by organization)
  allowedModels: (locator: ProjectLocator) =>
    [locator, "allowed-models"] as const,

  // Collections (scoped by connection)
  connectionCollections: (connectionId: string) =>
    [connectionId, "collections", "discovery"] as const,

  // Tool call results (generic caching for MCP tool calls)
  // scope is required - scopes the cache (connectionId for connection-scoped, locator for org/project-scoped)
  toolCall: (scope: string, toolName: string, paramsKey: string) =>
    ["tool-call", scope, toolName, paramsKey] as const,

  // Collection items (scoped by connection and collection name)
  collectionItems: (connectionId: string, collectionName: string) =>
    ["collection", connectionId, collectionName] as const,

  // Collection CRUD queries (scoped by orgId, scopeKey, client, and collection name)
  // orgId: organization ID
  // scopeKey: connectionId for connection-scoped tools, virtualMcpId/gatewayId for scoped tools, etc.
  // client: MCP client instance for cache isolation
  // Base prefix for invalidating all collection variants
  collection: (orgId: string, scopeKey: string, collectionName: string) =>
    [orgId, scopeKey, "collection", collectionName] as const,
  // Item query
  collectionItem: (
    client: unknown,
    orgId: string,
    scopeKey: string,
    collectionName: string,
    itemId: string,
  ) => [client, orgId, scopeKey, "collection", collectionName, itemId] as const,
  // List query
  collectionList: (
    client: unknown,
    orgId: string,
    scopeKey: string,
    collectionName: string,
    paramsKey: string,
  ) =>
    [
      client,
      orgId,
      scopeKey,
      "collection",
      collectionName,
      "list",
      paramsKey,
    ] as const,
  // Infinite list query
  collectionListInfinite: (
    client: unknown,
    orgId: string,
    scopeKey: string,
    collectionName: string,
    paramsKey: string,
  ) =>
    [
      client,
      orgId,
      scopeKey,
      "collection",
      collectionName,
      "list-infinite",
      paramsKey,
    ] as const,

  // Monitoring queries
  monitoringStats: () => ["monitoring", "stats"] as const,
  monitoringStatsToolCalls: (orgId: string, paramsKey: string) =>
    ["MONITORING_STATS", orgId, "tool-calls", paramsKey] as const,
  monitoringStatsLlm: (orgId: string, paramsKey: string) =>
    ["MONITORING_STATS", orgId, "llm", paramsKey] as const,
  monitoringThreadUsage: (locator: string, paramsKey: string) =>
    ["MONITORING_THREAD_USAGE", locator, paramsKey] as const,
  monitoringLogs: (filters: {
    connectionId?: string;
    toolName?: string;
    isError?: boolean;
    limit?: number;
    offset?: number;
  }) => ["monitoring", "logs", filters] as const,
  monitoringLogsInfinite: (locator: string, paramsKey: string) =>
    ["monitoring", "logs-infinite", locator, paramsKey] as const,
  monitoringLogDetail: (logId: string) =>
    ["monitoring", "log-detail", logId] as const,

  // Ensure-task query (load-or-create by id)
  ensureTask: (orgId: string, id: string) =>
    ["ensure-task", orgId, id] as const,

  // One-shot refresh of a viewed thread's metadata (read-only teammate threads)
  viewedThreadMetadataRefresh: (orgId: string, id: string) =>
    ["viewed-thread-metadata-refresh", orgId, id] as const,

  // Global search (server-side, scoped by org)
  globalSearch: (orgId: string, query: string) =>
    ["global-search", orgId, query] as const,

  // Thread queries (scoped by locator)
  threadsInfinite: (locator: string, paramsKey: string) =>
    ["threads", "list-infinite", locator, paramsKey] as const,
  overviewThreads: (locator: string) =>
    ["threads", "overview", locator] as const,
  threadMessages: (locator: string, threadId: string) =>
    ["threads", "messages", locator, threadId] as const,
  threadModelLogs: (locator: string, dateKey: string) =>
    ["threads", "model-logs", locator, dateKey] as const,
  threadSandbox: (orgKey: string, taskId: string | undefined) =>
    ["thread-sandbox", "v2", orgKey, taskId] as const,
  threadOutputs: (threadId: string) => ["thread-outputs", threadId] as const,
  // Fetched text content of a previewed file (FilePreview), keyed by URL.
  fileText: (downloadUrl: string) => ["file-text", downloadUrl] as const,
  // First bytes of a CSV/TSV file for the card thumbnail (range request).
  csvThumb: (downloadUrl: string) => ["csv-thumb", downloadUrl] as const,

  toolDefinitionLookup: (
    connectionId: string | null,
    orgId: string,
    rawToolName: string | null,
  ) =>
    [
      "virtual-mcp",
      orgId,
      connectionId ?? "default",
      "tools",
      "lookup",
      rawToolName,
    ] as const,

  // Virtual MCP agents (for agent mentions in chat)
  virtualMcpAgents: (orgId: string) =>
    ["virtual-mcp", orgId, "agents"] as const,

  // Virtual MCP prompts (for ice breakers in chat)
  // null virtualMcpId means default virtual MCP
  virtualMcpPrompts: (virtualMcpId: string | null, orgId: string) =>
    ["virtual-mcp", orgId, virtualMcpId ?? "default", "prompts"] as const,

  // Virtual MCP resources (for resource mentions in chat)
  // null virtualMcpId means default virtual MCP
  virtualMcpResources: (virtualMcpId: string | null, orgId: string) =>
    ["virtual-mcp", orgId, virtualMcpId ?? "default", "resources"] as const,

  // Suggestion menu items (for filtering prompts/resources in chat input)
  // Note: The hook appends `show` and `query` to this base key
  suggestionItems: (
    baseKey: readonly unknown[],
    isOpen: boolean,
    query: string,
  ) => [...baseKey, isOpen, query] as const,

  // Connection prompts (for Virtual MCP settings)
  connectionPrompts: (connectionId: string) =>
    ["connection", connectionId, "prompts"] as const,

  // Connection resources (for Virtual MCP settings)
  connectionResources: (connectionId: string) =>
    ["connection", connectionId, "resources"] as const,

  // User data
  user: (userId: string) => ["user", userId] as const,

  // Store README fetched from external URL
  storeReadmeUrl: (readmeUrl: string | null | undefined) =>
    ["store-readme-url", readmeUrl] as const,

  // Remote MCP tools (for store server detail page)
  remoteMcpTools: (remoteUrl: string | null) =>
    ["remote-mcp-tools", remoteUrl] as const,

  // Tags (scoped by locator)
  tags: (locator: string) => [locator, "tags"] as const,
  memberTags: (locator: string, memberId: string) =>
    [locator, "member-tags", memberId] as const,

  // Automations (scoped by organization, optionally by project)
  automationsAll: (organizationId: string) =>
    ["automations", organizationId] as const,
  automations: (organizationId: string, virtualMcpId?: string | null) =>
    ["automations", organizationId, virtualMcpId ?? null] as const,
  automation: (organizationId: string, id: string) =>
    ["automation", organizationId, id] as const,
  automationRuns: (
    organizationId: string,
    automationId: string,
    triggerIds?: string[],
  ) =>
    [
      "automation-runs",
      organizationId,
      automationId,
      ...[...(triggerIds ?? [])].sort(),
    ] as const,
  automationRunStats: (
    organizationId: string,
    automationId: string,
    paramsKey: string,
  ) =>
    ["automation-run-stats", organizationId, automationId, paramsKey] as const,

  // Projects (scoped by organization)
  projects: (organizationId: string) => ["projects", organizationId] as const,
  project: (organizationId: string, slug: string) =>
    ["project", organizationId, slug] as const,
  // Virtual MCP entity (scoped by org + id)
  virtualMcp: (orgId: string, virtualMcpId: string) =>
    ["virtual-mcp", orgId, virtualMcpId] as const,

  // Project plugin configs
  projectPluginConfigs: (projectId: string) =>
    ["project-plugin-configs", projectId] as const,
  projectPluginConfig: (projectId: string, pluginId: string) =>
    ["project-plugin-config", projectId, pluginId] as const,

  // Project connections (dependencies)
  projectConnections: (projectId: string) =>
    ["project-connections", projectId] as const,

  // Project connection details (with tools, for sidebar)
  projectConnectionDetails: (projectId: string, connectionIds: string[]) =>
    ["project-connections", projectId, "details", connectionIds] as const,

  // AI providers (static registry — staleTime: Infinity recommended)
  aiProviders: (orgId: string) => ["ai-providers", orgId] as const,

  // AI provider models (scoped by keyId)
  aiProviderModels: (orgId: string, keyId: string) =>
    ["ai-provider-models", orgId, keyId] as const,

  // AI provider stored keys (scoped by org)
  aiProviderKeys: (orgId: string) => ["ai-provider-keys", orgId] as const,
  // The caller's own linked Claude subscription (per user, but the tool call is
  // org-scoped, so the key is too).
  claudeSubscription: (orgId: string) =>
    ["claude-subscription", orgId] as const,
  aiProviderKeyPreview: (keyId: string) =>
    ["ai-provider-key-preview", keyId] as const,

  // Secrets (scoped by org; user-scope filtering happens server-side)
  secrets: (orgId: string) => ["secrets", orgId] as const,

  // Org-scoped S3 bucket file configurations
  fileConfigs: (orgId: string) => ["file-configs", orgId] as const,

  // Organization filesystem (volume browser). `orgFsVolume` is the prefix key
  // a mutation invalidates to refresh every listing + usage for the volume.
  orgFsVolume: (orgId: string, volume: string) =>
    ["org-fs", orgId, volume] as const,
  orgFsList: (orgId: string, volume: string, path: string) =>
    ["org-fs", orgId, volume, "list", path] as const,
  orgFsUsage: (orgId: string, volume: string) =>
    ["org-fs", orgId, volume, "usage"] as const,
  orgFsStat: (orgId: string, volume: string, path: string) =>
    ["org-fs", orgId, volume, "stat", path] as const,
  orgFsPublicSets: (orgId: string) => ["org-fs-public-sets", orgId] as const,
  // Cross-volume recent-files feed (Library home). Separate root key so a
  // volume named like the segment can never collide; mutations invalidate it
  // explicitly alongside the volume prefix.
  orgFsRecent: (orgId: string) => ["org-fs-recent", orgId] as const,
  // Path search (Library search box) — cross-volume, or narrowed to one
  // volume + directory subtree when browsing inside a folder. The root key is
  // the prefix mutations invalidate; per-query keys nest under it.
  orgFsSearchRoot: (orgId: string) => ["org-fs-search", orgId] as const,
  orgFsSearch: (orgId: string, query: string, volume: string, prefix: string) =>
    ["org-fs-search", orgId, query, volume, prefix] as const,
  // Skill folders (dirs with SKILL.md) across home + public sets — the
  // attachable-skill set for agent knowledge.
  orgFsSkills: (orgId: string) => ["org-fs-skills", orgId] as const,

  // Full skill catalog for the chat "/" picker. Distinct from `orgFsSkills`
  // (same endpoint, but that caches a stripped {volume,path} shape) — reusing
  // its key would collide two writers with incompatible payloads.
  slashSkills: (orgId: string) => ["slash-skills", orgId] as const,

  // File picker — objects listed from a configured bucket
  filePickerObjects: (
    orgId: string,
    configId: string | null,
    search?: string,
    imageOnly?: boolean,
  ) =>
    [
      "file-picker-objects",
      orgId,
      configId,
      search ?? "",
      imageOnly ?? false,
    ] as const,

  // AI provider credits balance (scoped by org + keyId)
  aiProviderCredits: (orgId: string, keyId: string) =>
    ["ai-provider-credits", orgId, keyId] as const,

  // Organization SSO
  orgSsoConfig: (organizationId: string) =>
    ["org-sso-config", organizationId] as const,
  orgSsoStatus: (organizationId: string) =>
    ["org-sso-status", organizationId] as const,

  // Store discovery (per-registry infinite query)
  storeDiscovery: (orgId: string, registryId: string) =>
    ["store-discovery", orgId, registryId] as const,

  // Organization domains (scoped by organization)
  organizationDomains: (organizationId: string) =>
    ["organization-domains", organizationId] as const,

  // Pending join requests (scoped by organization)
  organizationJoinRequests: (organizationId: string) =>
    ["organization-join-requests", organizationId] as const,

  // Domain lookup (for onboarding — scoped by email domain)
  domainLookup: (domain: string) => ["domain-lookup", domain] as const,

  // Deployment admin dashboard (instance-level, not org-scoped)
  deploymentAdminMe: () => ["deployment-admin", "me"] as const,
  deploymentAdminUsers: (search: string) =>
    ["deployment-admin", "users", search] as const,
  deploymentAdminOrgs: (search: string) =>
    ["deployment-admin", "orgs", search] as const,
  // Prefix key: invalidates every orgs query regardless of the search term.
  deploymentAdminOrgsList: () => ["deployment-admin", "orgs"] as const,

  // Brand context (scoped by organization)
  brandContext: (organizationId: string) =>
    ["brand-context", organizationId] as const,
  defaultBrand: (organizationId: string) =>
    ["brand-context", organizationId, "default"] as const,

  // Deco profile (scoped by user email)
  decoProfile: (email: string | undefined) => ["deco-profile", email] as const,

  // Deco sites (scoped by user email)
  decoSites: (email: string | undefined) => ["deco-sites", email] as const,
  decoApps: () => ["deco-apps"] as const,

  // Web search blob content (fetched from object storage)
  webSearchBlob: (url: string) => ["web-search-blob", url] as const,

  // Deco sections editor (sandbox preview)
  decofile: (previewUrl: string) => ["decofile", previewUrl] as const,
  // Variadic so an invalidation call can pass just the org/vmid/branch prefix
  // and still partial-match the full org/vmid/branch/previewUrl query key.
  liveMeta: (...parts: string[]) => ["live-meta", ...parts] as const,
  sandboxInvoke: (sandboxKey: string, loaderKey: string) =>
    ["sandbox-invoke", sandboxKey, loaderKey] as const,
  sandboxRepoDir: (orgSlug: string, virtualMcpId: string, branch: string) =>
    ["sandbox-repo-dir", orgSlug, virtualMcpId, branch] as const,
  // icon-select previews: the site's /sprites.svg, fetched via the preview proxy
  sandboxSprite: (sandboxKey: string) =>
    ["sandbox-sprite", sandboxKey] as const,

  // Native-only coding-agent availability; process-wide, not org-scoped.
  localAgentCapabilities: () => ["local-agent-capabilities"] as const,

  // GitHub integration
  githubUserOrgs: (orgId: string, connectionId: string) =>
    ["github-user-orgs", orgId, connectionId] as const,
  githubOrgRepos: (
    orgId: string,
    connectionId: string,
    installationLogin: string,
    query: string,
  ) =>
    [
      "github-org-repos",
      orgId,
      connectionId,
      installationLogin,
      query,
    ] as const,
  vmEnv: (orgSlug: string, virtualMcpId: string, branch: string) =>
    ["vm-env", orgSlug, virtualMcpId, branch] as const,

  // Desktop app (Tauri) only — the Keychain auth-status gate read by
  // `apps/web/src/desktop/use-desktop-auth.ts`. Lives here because
  // `plugins/enforce-query-key-constants.ts` requires every query key to be a
  // constant in this registry; it never appears in the web build's cache.
  desktopAuthStatus: () => ["desktop", "auth-status"] as const,
} as const;

export function invalidateVirtualMcpQueries(
  queryClient: import("@tanstack/react-query").QueryClient,
  orgId?: string,
) {
  queryClient.invalidateQueries({
    predicate: (query) => {
      const key = query.queryKey;
      return (
        (!orgId || key[1] === orgId) &&
        key[3] === "collection" &&
        key[4] === "VIRTUAL_MCP"
      );
    },
  });
}

export function invalidateConnectionQueries(
  queryClient: import("@tanstack/react-query").QueryClient,
  orgId?: string,
) {
  queryClient.invalidateQueries({
    predicate: (query) => {
      const key = query.queryKey;
      return (
        (!orgId || key[1] === orgId) &&
        key[3] === "collection" &&
        key[4] === "CONNECTIONS"
      );
    },
  });
}
