"""
Compounding Memory (wiki) read path.

v1 is strictly user-scoped: every read requires both `tenantId` and
`userId`. See .prds/compounding-memory-scoping.md.
"""
enum WikiPageType {
  ENTITY
  TOPIC
  DECISION
}

type WikiPageSection {
  id: ID!
  sectionSlug: String!
  heading: String!
  bodyMd: String!
  position: Int!
  lastSourceAt: AWSDateTime
}

type WikiPage {
  id: ID!
  tenantId: ID!
  userId: ID!
  ownerId: ID! @deprecated(reason: "Use userId")
  type: WikiPageType!
  """
  Approved ontology entity type slug materialized for this page, for example
  `customer`, `person`, `place`, or `support_case`. Null only for legacy or
  non-ontology pages.
  """
  entitySubtype: String
  """
  Human-readable type label for list/detail surfaces. Uses the approved
  ontology entity type when present; falls back to the legacy page type.
  """
  displayType: String!
  slug: String!
  title: String!
  summary: String
  bodyMd: String
  status: String!
  lastCompiledAt: AWSDateTime
  createdAt: AWSDateTime!
  updatedAt: AWSDateTime!
  sections: [WikiPageSection!]!
  aliases: [String!]!

  """
  Distinct memory_units (Hindsight records) that source at least one section
  on this page. Counts through `wiki_section_sources`. Hit on detail screens
  only — list screens must NOT request this (N+1 risk).
  """
  sourceMemoryCount: Int!
  """
  Up to `limit` memory_unit ids that source sections on this page, ordered
  by most recently-cited. Server-side capped at 50. Pairs with
  `MemoryRecord` drill-in so a page's "Based on N memories" badge can
  resolve to the actual records.
  """
  sourceMemoryIds(limit: Int = 10): [ID!]!
  """
  Parent hub when this page was promoted from a section on another page.
  Null for top-level pages. Reads `wiki_pages.parent_page_id`.
  """
  parent: WikiPage
  """
  Pages that were promoted out of this page's sections — the reverse of
  `parent`. Empty for pages that have never had a child promoted.
  """
  children: [WikiPage!]!
  """
  If this page was promoted out of a section on a parent page, the section
  it came from. Null when this page is top-level or the parent section has
  since been archived.
  """
  promotedFromSection: WikiPromotedFromSection
  """
  Active pages rolled up into this page's named section — the denormalized
  aggregation view (`aggregation.linked_page_ids` on the section jsonb).
  Empty when the section doesn't exist or carries no aggregation metadata.
  """
  sectionChildren(sectionSlug: String!): [WikiPage!]!
}

"""
Provenance linkage between a promoted page and the section it was derived
from. Populated only for pages whose `parent_page_id` is set AND whose
parent has a section in which `aggregation.promoted_page_id` points back.
"""
type WikiPromotedFromSection {
  parentPage: WikiPage!
  sectionSlug: String!
  sectionHeading: String!
}

type WikiSearchResult {
  page: WikiPage!
  score: Float!
  matchedAlias: String
}

type WikiCompileJob {
  id: ID!
  tenantId: ID!
  userId: ID!
  ownerId: ID! @deprecated(reason: "Use userId")
  status: String!
  trigger: String!
  dedupeKey: String!
  attempt: Int!
  claimedAt: AWSDateTime
  startedAt: AWSDateTime
  finishedAt: AWSDateTime
  error: String
  metrics: AWSJSON
  createdAt: AWSDateTime!
}

"""
User-scoped force-graph payload: all active pages and their [[...]] links
  for one `(tenant, user)` scope. Shaped to match the legacy `memoryGraph`
wire contract so the admin force-graph component can swap data sources
with minimal client changes. `type` is always `"page"` on nodes; the
Wiki page type (`ENTITY`/`TOPIC`/`DECISION`) lives in `entityType`.
"""
type WikiGraphNode {
  id: ID!
  label: String!
  type: String!
  entityType: WikiPageType!
  entitySubtype: String
  displayType: String!
  slug: String!
  strategy: String
  edgeCount: Int!
  latestThreadId: String
}

type WikiGraphEdge {
  source: ID!
  target: ID!
  kind: String!
  label: String!
  weight: Float!
}

type WikiGraph {
  nodes: [WikiGraphNode!]!
  edges: [WikiGraphEdge!]!
}

extend type Query {
  """
  Read one compiled page by slug. `userId` is required.
  """
  wikiPage(
    tenantId: ID!
    userId: ID
    ownerId: ID
    type: WikiPageType!
    slug: String!
  ): WikiPage

  """
  Postgres full-text search over compiled pages in a single (tenant, user)
  scope. Also matches exact aliases. Ranked by ts_rank + alias-hit boost.
  """
  wikiSearch(
    tenantId: ID!
    userId: ID
    ownerId: ID
    query: String!
    limit: Int = 20
  ): [WikiSearchResult!]!

  """
  Pages that link to the given page. Visibility is derived from the target
  page's owner scope; caller must be that owner or an admin.
  """
  wikiBacklinks(pageId: ID!): [WikiPage!]!

  """
  Pages this page links OUT to — the "Connected Pages" surface. Mirrors
  wikiBacklinks in the opposite direction; reads wiki_page_links where
  from_page_id = pageId. Deduplicated by target so a parent/child pair
  with both a `reference` link and a `parent_of` link returns once.
  """
  wikiConnectedPages(pageId: ID!): [WikiPage!]!

  """
  Admin-only: list recent compile jobs for a tenant. When `userId` is
  provided, restricts to that user's jobs; when null/absent, returns
  jobs across every user in the tenant. Ordered newest-first.

  Powers the `thinkwork wiki status` CLI command.
  """
  wikiCompileJobs(
    tenantId: ID!
    userId: ID
    ownerId: ID
    limit: Int = 10
  ): [WikiCompileJob!]!

  """
  User-scoped force-graph: every active wiki page + every page-to-page
  link whose endpoints are both active in the same `(tenant, user)`
  scope. Links that reference archived pages are excluded. One round-trip.
  """
  wikiGraph(tenantId: ID!, userId: ID, ownerId: ID): WikiGraph!
}

"""
Dispatch acknowledgement for `bootstrapJournalImport`. The actual ingest
runs on a dedicated worker Lambda (`wiki-bootstrap-import`) because
Hindsight's LLM-backed retain is too slow to complete within API Gateway's
30-second HTTP ceiling. Operator watches CloudWatch + wiki_compile_jobs
for the terminal compile the ingest enqueues.
"""
type WikiJournalImportDispatch {
  accountId: ID!
  tenantId: ID!
  userId: ID!
  agentId: ID @deprecated(reason: "Use userId")
  dispatched: Boolean!
  error: String
  dispatchedAt: AWSDateTime!
}

type WikiResetCursorResult {
  tenantId: ID!
  userId: ID!
  ownerId: ID! @deprecated(reason: "Use userId")
  cursorCleared: Boolean!
  pagesArchived: Int!
  dryRun: Boolean!
  brainIncluded: Boolean!
  impact: AWSJSON
}

extend type Mutation {
  """
  Admin-only: enqueue an ad-hoc compile job for a specific (tenant, user).
  Returns the job row (newly inserted or the in-flight dedupe hit).

  When `modelId` is supplied, it is forwarded to the compile Lambda event
  payload so a single run can override `BEDROCK_MODEL_ID` without a
  redeploy. The override takes effect only on the direct Event-invoke
  path; if the invoke fails and a polling worker claims the job later, the
  compile falls back to the env-default model.
  """
  compileWikiNow(
    tenantId: ID!
    userId: ID
    ownerId: ID
    modelId: String
    forceNew: Boolean = false
  ): WikiCompileJob!

  """
  Admin-only fire-and-forget dispatch of a journal-schema bulk ingest onto
  a dedicated worker Lambda. Returns immediately with a dispatch
  acknowledgement — the actual ingest + terminal compile happen
  asynchronously. Track progress via the wiki-bootstrap-import Lambda's
  CloudWatch logs and the resulting compile job in wiki_compile_jobs.
  """
  bootstrapJournalImport(
    accountId: ID!
    tenantId: ID!
    userId: ID
    agentId: ID
    limit: Int
  ): WikiJournalImportDispatch!

  """
  Admin-only replay: clear the compile cursor for (tenant, user). If
  `force` is true, also archives every active page in the scope so the
  next compile rebuilds from scratch. Destructive when force=true.
  """
  resetWikiCursor(
    tenantId: ID!
    userId: ID
    ownerId: ID
    force: Boolean = false
    dryRun: Boolean = false
    includeBrain: Boolean = false
  ): WikiResetCursorResult!
}
