/**
 * @module tests/unit/graph/lsm-partial-load-failclosed
 * @description LSMTree partial-load fail-closed guard (Finding 3 of the honest
 * index-readiness spine plan). `loadSSTables()` used to swallow a per-SSTable
 * load failure with only a `prodLog.warn`, then `loadManifest()` still published
 * the FULL persisted `totalRelationships` count — so on a partial cold load,
 * `size()`/`isHealthy()` reported the full count and "healthy" while a subset of
 * the tree's edges were silently unqueryable. Fixed by failing the whole load
 * closed on ANY per-SSTable failure: `loadManifest()`'s existing catch then
 * resets `sstables`/`totalRelationships`/`sstablesByLevel` to honest-empty, so
 * `size()` reports 0 and the graph layer's existing `size()===0` self-heal
 * rebuilds from canonical records — the dishonest partial state can no longer be
 * observed.
 */
import { describe, it, expect } from 'vitest'
import { LSMTree } from '../../../src/graph/lsm/LSMTree.js'
import { MemoryStorage } from '../../../src/storage/adapters/memoryStorage.js'

describe('LSMTree partial SSTable load fails closed (honest size())', () => {
  it('one SSTable fails to load → size() reports 0, not the manifest count', async () => {
    const storage = new MemoryStorage()
    await storage.init()
    const prefix = 'test-lsm-partial'

    const t1 = new LSMTree(storage, { storagePrefix: prefix, enableCompaction: false })
    await t1.init()
    await t1.add('a', 'b'); await t1.flush()   // SSTable #1
    await t1.add('c', 'd'); await t1.flush()   // SSTable #2
    expect(t1.size()).toBeGreaterThanOrEqual(2)
    await t1.close()

    // Find an SSTable id from the persisted manifest.
    const manifest = await storage.getMetadata(`${prefix}-manifest`)
    const sstableIds = Object.keys((manifest!.data as any).sstables)
    expect(sstableIds.length).toBeGreaterThanOrEqual(2)

    // Reopen with ONE SSTable load forced to fail (deterministic).
    const t2 = new LSMTree(storage, { storagePrefix: prefix, enableCompaction: false })
    const realGet = storage.getMetadata.bind(storage)
    ;(storage as any).getMetadata = async (key: string) => {
      if (key === `${prefix}-${sstableIds[1]}`) throw new Error('simulated SSTable load failure')
      return realGet(key)
    }
    await t2.init()

    // BEFORE THE FIX: t2.size() === (full manifest count)  ← LIE (partial load, full count)
    // AFTER THE FIX:  t2.size() === 0                       ← fail-closed → self-heal rebuilds
    expect(t2.size()).toBe(0)
    expect(t2.isHealthy()).toBe(true) // honestly-empty-but-initialized, not "healthy with a lie"

    await t2.close()
  })

  it('a clean load with no failures still reports the full honest count', async () => {
    const storage = new MemoryStorage()
    await storage.init()
    const prefix = 'test-lsm-clean'

    const t1 = new LSMTree(storage, { storagePrefix: prefix, enableCompaction: false })
    await t1.init()
    await t1.add('a', 'b'); await t1.flush()
    await t1.add('c', 'd'); await t1.flush()
    const expectedSize = t1.size()
    expect(expectedSize).toBeGreaterThanOrEqual(2)
    await t1.close()

    // Reopen with no injected failures — a normal, fully-successful cold load.
    const t2 = new LSMTree(storage, { storagePrefix: prefix, enableCompaction: false })
    await t2.init()

    expect(t2.size()).toBe(expectedSize)
    expect(t2.isHealthy()).toBe(true)

    await t2.close()
  })
})
