import { defineTable } from 'convex/server';
import { v } from 'convex/values';

import { lifecycleStatusValidator } from '../governance/soft_delete_validators';
import { jsonRecordValidator } from '../lib/validators/json';

export const documentsTable = defineTable({
  organizationId: v.string(),
  title: v.optional(v.string()),
  content: v.optional(v.string()),
  fileId: v.optional(v.id('_storage')),
  mimeType: v.optional(v.string()),
  extension: v.optional(v.string()),
  // Open string. Equal to the integration slug for integration-sourced docs
  // (`onedrive`, `sharepoint`, `google_drive`, …); reserved values `upload` and
  // `agent` cover non-integration sources. New integrations require no schema
  // change.
  sourceProvider: v.optional(v.string()),
  externalItemId: v.optional(v.string()),
  siteId: v.optional(v.string()),
  driveId: v.optional(v.string()),
  contentHash: v.optional(v.string()),
  historyFiles: v.optional(v.array(v.id('_storage'))),
  teamId: v.optional(v.string()),
  /** @deprecated Use teamId instead. Kept for backward compatibility during migration. */
  teamTags: v.optional(v.array(v.string())),
  /** @deprecated Removed in single-team model. Kept for backward compatibility during migration. */
  sharedWithTeamIds: v.optional(v.array(v.string())),
  /**
   * Project this document belongs to. Mutually exclusive with `teamId`:
   * a doc is either a project doc, a team library doc, or an org library
   * doc (both null). Enforced in `attachDocumentToProject` /
   * `detachDocumentFromProject` (services/platform/convex/projects/mutations.ts).
   * RAG retrieval unions project docs via `getAgentScopedFileIds`.
   */
  projectId: v.optional(v.id('projects')),
  /**
   * @deprecated RAG indexing status is now canonical on
   * `fileMetadata.ragStatus` (join: `documents.fileId == fileMetadata.storageId`).
   * No longer written; read via `getDocumentRagProjection`. Kept optional for
   * backward compatibility with existing rows.
   */
  ragInfo: v.optional(
    v.object({
      status: v.union(
        v.literal('queued'),
        v.literal('running'),
        v.literal('completed'),
        v.literal('failed'),
      ),
      indexedAt: v.optional(v.number()),
      /** @deprecated No longer written; use document.fileId directly. Kept for backward compatibility. */
      indexedFileId: v.optional(v.id('_storage')),
      error: v.optional(v.string()),
      /** @deprecated No longer written, kept for backward compatibility with existing data. */
      jobId: v.optional(v.string()),
    }),
  ),
  /**
   * @deprecated Use `fileMetadata.ragStatus === 'completed'` (projected via
   * `getDocumentRagProjection`). No longer written.
   */
  indexed: v.optional(v.boolean()),
  scannedPagesDetected: v.optional(v.number()),
  ocrApplied: v.optional(v.boolean()),
  sourceCreatedAt: v.optional(v.number()),
  sourceModifiedAt: v.optional(v.number()),
  createdBy: v.optional(v.string()),
  folderId: v.optional(v.id('folders')),
  folderPath: v.optional(v.string()),
  metadata: v.optional(jsonRecordValidator),
  lifecycleStatus: v.optional(lifecycleStatusValidator),
  statusChangedAt: v.optional(v.number()),
})
  .index('by_organizationId', ['organizationId'])
  .index('by_organizationId_and_lifecycleStatus', [
    'organizationId',
    'lifecycleStatus',
  ])
  .index('by_organizationId_and_folderId', ['organizationId', 'folderId'])
  .index('by_organizationId_and_createdBy', ['organizationId', 'createdBy'])
  .index('by_organizationId_and_sourceProvider', [
    'organizationId',
    'sourceProvider',
  ])
  .index('by_organizationId_and_externalItemId', [
    'organizationId',
    'externalItemId',
  ])
  .index('by_organizationId_and_extension', ['organizationId', 'extension'])
  .index('by_organizationId_and_title', ['organizationId', 'title'])
  // Bounded exact-match lookup for the WebDAV .trash resolver: find a
  // trashed doc by title without collecting every trashed row in the org.
  .index('by_org_lifecycle_title', [
    'organizationId',
    'lifecycleStatus',
    'title',
  ])
  // Bounded name-collision / leaf-resolve lookup for WebDAV: docs with an
  // exact title in an exact folder (0-1 active in practice). Without the
  // folderId column, a name repeated across a synced tree (package.json,
  // .DS_Store, index.html) makes the (org,title) collect O(all-same-name).
  .index('by_org_title_folder', ['organizationId', 'title', 'folderId'])
  .index('by_organizationId_and_fileId', ['organizationId', 'fileId'])
  // @deprecated unused — RAG completion is now queried via fileMetadata
  // `by_organizationId_and_ragStatus`. Kept (deprecate-don't-delete) so
  // existing data + any in-flight code referencing it stays valid.
  .index('by_organizationId_and_indexed', ['organizationId', 'indexed'])
  .index('by_organizationId_and_folderPath', ['organizationId', 'folderPath'])
  // Projects feature: list documents attached to a project.
  .index('by_organizationId_and_projectId', ['organizationId', 'projectId']);
