// {{ display_name }} MCP server — generated by mcpify. Do not hand-edit.
//
// Populates a store db's semantic_endpoints vec0 table with real
// embedding vectors. mcpify's Rust generator only creates this table's
// schema (see the plan's embeddings decision) — this script is the single
// place vectors get computed, reusing the exact same embedding-service the
// `search` tool calls at runtime (src/services/embedding-service.ts), so
// indexing-time and live-query embeddings are guaranteed to share the same
// model and vector space.

import Database from 'better-sqlite3';
import * as sqliteVec from 'sqlite-vec';

import { VERSION_STORE_FILES } from '../src/data/store-repository.js';
import { embed } from '../src/services/embedding-service.js';

interface EndpointRow {
  operation_id: string;
  path: string;
  method: string;
  summary: string | null;
  description: string | null;
}

function resolveStorePath(fileName: string): string {
  return new URL(`../${fileName}`, import.meta.url).pathname;
}

// Which store file(s) to populate: bare invocation targets just
// mcp_store.db (the default version), matching every deployment that
// only ever ships that one file (this project's own Dockerfile
// included); an explicit filename targets exactly that file; --all
// walks every version this project's ledger knows about
// (VERSION_STORE_FILES) — the one-time local backfill needed after
// `mcpify add-version` adds a new version file, since each version's
// .db gets its own independent semantic_endpoints table.
function targets(): string[] {
  const args = process.argv.slice(2);
  if (args[0] === '--all') {
    return Object.values(VERSION_STORE_FILES);
  }
  if (args[0]) {
    return [args[0]];
  }
  return ['mcp_store.db'];
}

async function populateOne(fileName: string): Promise<void> {
  const db = new Database(resolveStorePath(fileName));
  sqliteVec.load(db);

  const rows = db
    .prepare('SELECT operation_id, path, method, summary, description FROM endpoints')
    .all() as EndpointRow[];

  // sqlite-vec's vec0 virtual tables don't implement conflict resolution
  // (no ON CONFLICT / INSERT OR REPLACE support — a duplicate primary key
  // always raises a UNIQUE constraint error), so re-running this script
  // against a db that already has rows requires an explicit delete before
  // each insert to stay idempotent.
  const del = db.prepare('DELETE FROM semantic_endpoints WHERE operation_id = ?');
  const insert = db.prepare('INSERT INTO semantic_endpoints (operation_id, embedding) VALUES (?, ?)');

  // Sequential, not parallelized: keeps peak memory bounded regardless of
  // how many operations a spec declares, at the cost of total wall time —
  // an acceptable trade for a one-time setup script.
  for (const row of rows) {
    const text = [row.method, row.path, row.summary, row.description].filter(Boolean).join(' ');
    const vector = await embed(text);
    del.run(row.operation_id);
    insert.run(row.operation_id, JSON.stringify(vector));
  }

  console.log(`populated embeddings for ${rows.length} operation(s) in '${fileName}'`);
  db.close();
}

async function main(): Promise<void> {
  for (const fileName of targets()) {
    await populateOne(fileName);
  }
}

main().catch((error) => {
  console.error('failed to populate embeddings:', error);
  process.exit(1);
});
