/**
 * ADR-121 Phase 5b — DiskannSnapshot tests.
 *
 * Tests run with the optional peer dep MOCKED ABSENT so we exercise
 * the named-error path deterministically. The "real backend"
 * end-to-end test (streaming insert → build → search → save → load)
 * runs in the CI smoke against the actual @ruvector/diskann module
 * when present.
 *
 * Acceptance:
 *   - DiskannSnapshot.create throws a clear, named error when the
 *     peer dep is missing
 *   - diskannAvailable() returns false (boolean, no throw)
 *   - Error message names the package + the RabitqSnapshot fallback
 *     so callers know what to do
 */

import { describe, it, expect, vi } from 'vitest';

// Force the peer-dep-missing path so tests don't depend on the NAPI
// binding shipping correctly for the test runner's OS/arch.
vi.mock('@ruvector/diskann', () => ({}));

import { DiskannSnapshot, diskannAvailable } from '../diskann-snapshot.js';

describe('DiskannSnapshot — peer-dep error contract', () => {
  it('create() throws a clear, named error when @ruvector/diskann missing', async () => {
    await expect(
      DiskannSnapshot.create({ dimension: 384 }),
    ).rejects.toThrow(/@ruvector\/diskann/);
  });

  it('error names the install command + the RabitqSnapshot fallback', async () => {
    await expect(
      DiskannSnapshot.create({ dimension: 384 }),
    ).rejects.toThrow(/npm install/);
    await expect(
      DiskannSnapshot.create({ dimension: 384 }),
    ).rejects.toThrow(/RabitqSnapshot/);
  });

  it('load() also throws with named error when peer dep missing', async () => {
    await expect(
      DiskannSnapshot.load('/tmp/nonexistent', { dimension: 384 }),
    ).rejects.toThrow(/@ruvector\/diskann/);
  });

  it('diskannAvailable returns false when peer dep absent', async () => {
    expect(await diskannAvailable()).toBe(false);
  });

  it('diskannAvailable returns a boolean (never throws)', async () => {
    const result = await diskannAvailable();
    expect(typeof result).toBe('boolean');
  });
});
