/**
 * Lane J — what storage does when the browser says no.
 *
 * In a Firefox/Safari private window `indexedDB` exists and `open()` then fires
 * onerror. The old availability check was `typeof indexedDB !== 'undefined'`,
 * which answered "yes, go ahead" and led to the whole editor being replaced by
 * an error string. Three properties are asserted here:
 *
 *   [1] availability is a real probe, so it says NO when open fails;
 *   [2] a failure is not memoised as a rejected promise — storage coming back
 *       (a different database, a granted permission) works without a reload;
 *   [3] an open that neither succeeds nor errors (a blocked upgrade) still
 *       settles, so nothing waits forever.
 *
 *   node --experimental-strip-types --import ./src/editor/node-ts-resolve.mjs \
 *        src/editor/idb-degrade.test.ts
 */

export {} // everything is loaded with await import(), so say "module" explicitly

type Mode = 'error' | 'ok' | 'silent'
let mode: Mode = 'error'

const stores = new Map<string, Map<string, unknown>>()

const fakeIndexedDb = {
  open(_name: string) {
    const req: Record<string, unknown> = {
      result: null, error: null, onsuccess: null, onerror: null,
      onupgradeneeded: null, onblocked: null,
    }
    if (mode === 'silent') return req // fires nothing, ever
    if (mode === 'error') {
      req.error = new Error('InvalidStateError: storage is not available here')
      queueMicrotask(() => void (req.onerror as (() => void) | null)?.())
      return req
    }
    const db = {
      objectStoreNames: { contains: (s: string) => stores.has(s) },
      createObjectStore: (s: string) => void stores.set(s, new Map()),
      transaction: () => ({ objectStore: () => ({}) }),
    }
    req.result = db
    queueMicrotask(() => {
      ;(req.onupgradeneeded as (() => void) | null)?.()
      ;(req.onsuccess as (() => void) | null)?.()
    })
    return req
  },
}
;(globalThis as unknown as { indexedDB: unknown }).indexedDB = fakeIndexedDb

const { idbAvailable, resetIdb, setDbName } = await import('./idb')

let passed = 0
function ok(cond: boolean, msg: string): void {
  if (!cond) throw new Error('FAIL: ' + msg)
  passed++
}

// ---- [1] a real probe, not a typeof check ----------------------------------
ok(typeof indexedDB !== 'undefined',
  '[1] the browser object exists (the old check would have said yes here)')
ok((await idbAvailable()) === false,
  '[1] but actually opening it fails, so availability is false')
ok((await idbAvailable()) === false, '[1] the answer is stable and cached')

// ---- [2] the failure is not permanent --------------------------------------
mode = 'ok'
resetIdb()
ok((await idbAvailable()) === true,
  '[2] once storage works, the same session gets a working database (no memoised rejection)')

// A different database name is a fresh question, never the old cached rejection.
mode = 'error'
setDbName('blobbo-workshop-demo')
ok((await idbAvailable()) === false, '[2] switching database re-asks the question')

// ---- [3] an open that never answers still settles --------------------------
mode = 'silent'
setDbName('blobbo-workshop-blocked')
const started = Date.now()
const answer = await idbAvailable()
ok(answer === false, '[3] a database that never answers is reported unavailable')
ok(Date.now() - started < 10_000,
  `[3] and it gives up rather than hanging (took ${Date.now() - started}ms)`)

console.log(`editor idb-degrade.test: ${passed} assertions passed ✓`)
