export class LazyNodeIdTable {
  constructor(bytes, offsets, options = {}) {
    this.bytes = bytes;
    this.offsets = offsets;
    this.length = Math.max(0, offsets.length - 1);
    this.decoder = options.decoder || new TextDecoder();
    this.cacheLimit = Number.isFinite(options.cacheLimit) ? options.cacheLimit : 0;
    this.cache = this.cacheLimit > 0 ? new Map() : null;
  }

  get(index) {
    if (index < 0 || index >= this.length) return undefined;
    if (this.cache && this.cache.has(index)) {
      const cached = this.cache.get(index);
      this.cache.delete(index);
      this.cache.set(index, cached);
      return cached;
    }
    const start = this.offsets[index];
    const end = this.offsets[index + 1];
    if (start === undefined || end === undefined || end < start) return undefined;
    // Garbage offset tables (caller-supplied buffer) can point far beyond
    // the byte section — a slice out of bounds would RangeError downstream
    // instead of degrading to a missing key.
    if (start > this.bytes.byteLength || end > this.bytes.byteLength) return undefined;
    const view = new Uint8Array(this.bytes.buffer, this.bytes.byteOffset + start, end - start);
    const value = this.decoder.decode(view);
    if (this.cache) {
      this.cache.set(index, value);
      if (this.cache.size > this.cacheLimit) {
        const oldestKey = this.cache.keys().next().value;
        this.cache.delete(oldestKey);
      }
    }
    return value;
  }
}
