/**
 * community blueprint · wiring seam for `@platform-modules/search`.
 *
 * Adapter-minimalism (CLAUDE.md §4): register ONE entity provider ('post') backed by an in-memory
 * list and expose searchEntities over it. A real host's provider runs a Postgres FTS query — the
 * module sanitizes the user query into a prefix-tsquery internally (`@platform-modules/util/fts`)
 * before the provider sees it. This seam proves a published post becomes findable through the SAME
 * searchEntities the host federates across its other entity types.
 *
 * Because searchEntities hands the provider the ALREADY-SANITIZED query (e.g. `launch:* & notes:*`),
 * this in-memory provider recovers the bare lexemes and AND-matches them (mirroring the `&` join) —
 * it must NOT substring-match the raw tsquery string.
 */
import {
  searchEntities,
  type Hit,
  type SearchProvider,
  type SearchRegistry,
  type SearchResult,
} from '@platform-modules/search'

export type IndexedPost = { id: string; title: string; body: string }

export type PostIndex = {
  /** Index a published post so it becomes findable. */
  add(post: IndexedPost): void
  /** The registry a host hands to searchEntities (here: a single 'post' provider). */
  registry: SearchRegistry<IndexedPost[]>
  /** Convenience: run searchEntities for the 'post' type with this index as ctx. */
  search(query: string): Promise<SearchResult>
}

/** Recover bare lexemes from a sanitized prefix-tsquery (`foo:* & bar:*` → `['foo','bar']`). */
function lexemes(sanitized: string): string[] {
  return sanitized
    .split('&')
    .map((token) => token.replace(/:\*/g, '').trim().toLowerCase())
    .filter(Boolean)
}

export function createPostIndex(): PostIndex {
  const posts: IndexedPost[] = []

  const postProvider: SearchProvider<IndexedPost[]> = async (query, ctx, window) => {
    const tokens = lexemes(query)
    const matched =
      tokens.length === 0
        ? []
        : ctx.filter((post) => {
            const haystack = `${post.title} ${post.body}`.toLowerCase()
            return tokens.every((token) => haystack.includes(token))
          })
    const hits: Hit[] = matched
      .slice(window.offset, window.offset + window.limit)
      .map((post, i) => ({ entityType: 'post', id: post.id, rank: 1 - i / 100, title: post.title }))
    return { hits, total: matched.length }
  }

  const registry: SearchRegistry<IndexedPost[]> = { post: postProvider }

  return {
    add(post) {
      posts.push(post)
    },
    registry,
    search(query) {
      return searchEntities(registry, { query, ctx: posts, entityTypes: ['post'], limit: 10 })
    },
  }
}
