/**
 * @module tests/unit/storage/sharding-new-installation-log
 * @description Regression for BR-8-BOOT-INDEX symptom 1. Brainy 8.0 stores
 * entities in the canonical `entities/nouns/<shard>/<id>/vectors.json` layout,
 * but the legacy sharding probe (`detectExistingShardingDepth`) inspected
 * `entities/nouns/hnsw` — a 7.x directory the 8.0 write path never populates —
 * so it returned null and logged "📁 New installation" for EVERY store on EVERY
 * boot, including established brains holding thousands of entities. The
 * new-vs-existing decision now consults the canonical layout the DB actually
 * uses (`hasCanonicalEntities`), so an established brain reports its true entity
 * count and only a genuinely empty store says "New installation".
 */
import { describe, it, expect, vi, afterEach } from 'vitest'
import { mkdtempSync, rmSync } from 'fs'
import { tmpdir } from 'os'
import { join } from 'path'
import { FileSystemStorage } from '../../../src/storage/adapters/fileSystemStorage.js'
import type { NounMetadata } from '../../../src/coreTypes.js'

const dirs: string[] = []
function mkTmp(): string {
  const d = mkdtempSync(join(tmpdir(), 'brainy-newinstall-'))
  dirs.push(d)
  return d
}
afterEach(() => {
  for (const d of dirs.splice(0)) rmSync(d, { recursive: true, force: true })
  vi.restoreAllMocks()
})

/** Release a raw FileSystemStorage so a subsequent open of the dir is unblocked. */
async function teardown(s: any): Promise<void> {
  try { await s.flush?.() } catch { /* best effort */ }
  try { s.stopFlushRequestWatcher?.() } catch { /* best effort */ }
  try { await s.releaseWriterLock?.() } catch { /* best effort */ }
}

/** Capture everything written to console.log during `fn()`. */
async function captureLog(fn: () => Promise<void>): Promise<string> {
  const lines: string[] = []
  const spy = vi
    .spyOn(console, 'log')
    .mockImplementation((...args: any[]) => {
      lines.push(args.map(String).join(' '))
    })
  try {
    await fn()
  } finally {
    spy.mockRestore()
  }
  return lines.join('\n')
}

const VEC = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]
async function seedOne(s: any, id: string): Promise<void> {
  await s.saveNounMetadata(id, {
    noun: 'thing',
    createdAt: Date.now(),
    updatedAt: Date.now()
  } as NounMetadata)
  await s.saveNoun({ id, vector: VEC, connections: new Map(), level: 0 })
}

describe('FileSystemStorage boot log: an established brain is not "New installation" (BR-8-BOOT-INDEX)', () => {
  it('a genuinely fresh store still logs "New installation"', async () => {
    const dir = mkTmp()
    const storage = new FileSystemStorage(dir)
    const out = await captureLog(() => storage.init())
    expect(out).toContain('New installation')
    await teardown(storage)
  })

  it('an established store (canonical entities present) does NOT log "New installation" on reopen', async () => {
    const dir = mkTmp()

    // 1. Author an entity → canonical entities/nouns/<shard>/<id>/vectors.json.
    const first = new FileSystemStorage(dir)
    await first.init()
    await seedOne(first, 'a'.repeat(32))
    await teardown(first)

    // 2. Reopen: the boot log must reflect the established store, not "New installation".
    const second = new FileSystemStorage(dir)
    const out = await captureLog(() => second.init())
    expect(out).not.toContain('New installation')
    expect(out).toContain('Using depth 1 sharding')
    await teardown(second)
  })

  it('counts RECOVER from the canonical layout when counts.json is lost (container-restart case)', async () => {
    const dir = mkTmp()

    // Establish a store with 3 entities (canonical layout + counts.json).
    const first: any = new FileSystemStorage(dir)
    await first.init()
    for (const c of ['a', 'b', 'c']) await seedOne(first, c.repeat(32))
    await teardown(first)

    // Simulate the lost/corrupted counts.json a container restart can leave.
    for (const f of ['counts.json', 'counts.json.gz']) {
      rmSync(join(dir, '_system', f), { force: true })
    }

    // Reopen: the recovery scan must count the CANONICAL tree. The removed
    // implementation scanned the vestigial `entities/*/hnsw` dirs and
    // re-initialized every counter to ZERO on real data.
    const second: any = new FileSystemStorage(dir)
    await second.init()
    expect(await second.getNounCount()).toBe(3)
    await teardown(second)
  })

  it('hasCanonicalEntities() sees the canonical shard tree — independent of counts.json', async () => {
    const dir = mkTmp()
    const s: any = new FileSystemStorage(dir)
    await s.init()

    // Fresh: only the vestigial `hnsw` dir exists → no canonical entities.
    expect(await s.hasCanonicalEntities()).toBe(false)

    // After a canonical write the 2-hex shard dir exists → established, even if
    // counts.json were later lost on a container restart (the fallback path).
    await seedOne(s, 'c'.repeat(32))
    expect(await s.hasCanonicalEntities()).toBe(true)

    await teardown(s)
  })
})
