'use strict';

/**
 * Shared registry primitive — Map<id, entry> with deregister-closure pattern.
 *
 * Same shape used 5 times in skill-dispatch deep-dive (sandbox-registry,
 * internal-skill-registry, harness-registry, trigger-registry, snapshot-registry).
 * Centralizing here so providers/channels/adapters/plugin-loader all share
 * the same structure.
 *
 * Each entry must have an `id` field. `register()` returns a deregister
 * function — call it to remove the entry without holding a reference to the
 * registry itself.
 *
 * Diagnostics: registries can opt to report load-time failures via the
 * shared diagnostics surface (see plugins/diagnostics.js, Item F).
 */

class Registry {
  /**
   * @param {string} kind - Registry kind label (for diagnostics: "provider", "channel", ...)
   */
  constructor(kind) {
    this.kind = kind || 'plugin';
    this._entries = new Map();
  }

  /**
   * Register an entry. Throws if id already taken (override with replace=true).
   * Returns a deregister closure.
   *
   * @param {object} entry - Must have `id` (string)
   * @param {object} [opts]
   * @param {boolean} [opts.replace=false] - Allow overwriting existing entry
   * @returns {() => boolean} - Call to remove. Returns true if removed.
   */
  register(entry, opts = {}) {
    if (!entry || typeof entry.id !== 'string' || !entry.id) {
      throw new Error(`[registry:${this.kind}] entry.id is required`);
    }
    if (!opts.replace && this._entries.has(entry.id)) {
      throw new Error(
        `[registry:${this.kind}] id already registered: ${entry.id}`
      );
    }
    this._entries.set(entry.id, entry);
    return () => this._entries.delete(entry.id);
  }

  /** Get entry by id, or undefined. */
  get(id) {
    return this._entries.get(id);
  }

  /** Has this id? */
  has(id) {
    return this._entries.has(id);
  }

  /** All entries as an array, in insertion order. */
  list() {
    return Array.from(this._entries.values());
  }

  /** All ids. */
  ids() {
    return Array.from(this._entries.keys());
  }

  /** Number of registered entries. */
  size() {
    return this._entries.size;
  }

  /** Remove all entries. Used in tests. */
  clear() {
    this._entries.clear();
  }
}

module.exports = { Registry };
