// `searchDocs` — the retrieval tool the support agent calls.
//
// Tool shape (the `*.tool.tsx` convention): a named `defineTool(...)`
// DESCRIPTOR with the Schema-typed `input` / `output` and NO body, plus
// a default-exported `(input, ctx) => …` handler. The framework wires
// the default export onto the descriptor at discovery time, and the
// agent's `tools: { searchDocs }` imports the SAME module instance.
//
// This file is SERVER-ONLY — it's referenced from the agent EXECUTOR
// (`support.agent.server.tsx`), never from a browser-loaded descriptor,
// so importing the `database` handle here is safe.
//
// The handler does vector retrieval: `database.docs.nearestNeighbours(
// query, k)` returns the k nearest docs (each row gets a synthetic
// `distance`). Because `docs` carries `vectorEmbedding()`, the STRING
// overload is valid — the runtime embeds `query` before searching. Any
// failure (no AI key, embed error) is caught → empty array, so a tool
// hiccup surfaces to the model as "no results" instead of aborting the
// whole agent turn.

import { defineTool } from '@voltro/ai'
import type { AppContext } from '@voltro/runtime'
import { Schema } from 'effect'
import { database } from '../database/schema'

const MAX_RESULTS = 5
const SNIPPET_LEN = 280

export const searchDocs = defineTool({
  name:        'searchDocs',
  description:
    'Search the support knowledge base for documents relevant to a question. ' +
    'Returns up to 5 results, each with a title and a short snippet of the body.',
  input:  Schema.Struct({ query: Schema.String }),
  output: Schema.Array(
    Schema.Struct({ title: Schema.String, snippet: Schema.String }),
  ),
})

export default async (
  { query }: { query: string },
  ctx: AppContext,
): Promise<ReadonlyArray<{ title: string; snippet: string }>> => {
  try {
    const rows = await ctx.store.query(
      database.docs.nearestNeighbours(query, MAX_RESULTS).descriptor,
    )
    return rows.map((row) => {
      const body = String((row as { body?: unknown }).body ?? '')
      return {
        title:   String((row as { title?: unknown }).title ?? ''),
        snippet: body.length > SNIPPET_LEN ? `${body.slice(0, SNIPPET_LEN)}…` : body,
      }
    })
  } catch {
    // No AI key / embed failure / cold table → degrade to "no results"
    // rather than aborting the agent's tool loop.
    return []
  }
}
