// Block registry (client side) — mirrors the server registry
// (server/src/blocks/registry.js) but carries the browser-only concerns: the
// React renderer, the admin edit form, and the palette icon/label. The page
// builder's palette, drag-reorder canvas, per-block edit panel, and the public
// page renderer all read from this registry, so adding a block later is one
// entry here (plus its server-side schema entry) rather than edits scattered
// across the builder and renderer.
//
// A registered definition looks like:
//   {
//     type: 'heading',       // must match the server registry type
//     version: 1,            // must match the server schema version
//     label: 'Heading',      // palette display name
//     icon: 'heading',       // palette icon key
//     component: HeadingBlock,   // renderer: (props) => JSX
//     editor: HeadingEditor,     // admin edit form: ({ props, onChange }) => JSX
//     defaults: () => ({ ... }), // starting props when a block is added
//     container: false,          // true only for two_column
//     containerSlots: [],        // ['left','right'] for two_column
//   }
//
// This module only defines the pattern; Wave 1 definitions register via
// ./index.js as each block is built (spec build order step 3).

const registry = new Map()

// Kept in sync with the server's RESERVED_KEYS — the only top-level keys on a
// stored block object. Exported so the builder can construct envelopes without
// hard-coding the shape.
export const RESERVED_KEYS = ['id', 'type', 'version', 'visible', 'props']

/**
 * Register a block definition. Throws on a duplicate type — a programmer error
 * caught at module load, not runtime.
 * @param {object} def
 * @returns {object} the stored definition
 */
export function registerBlock(def) {
  if (!def || typeof def.type !== 'string' || def.type.length === 0) {
    throw new Error('registerBlock: a block definition needs a string `type`')
  }
  if (registry.has(def.type)) {
    throw new Error(`registerBlock: block type already registered: ${def.type}`)
  }
  const entry = {
    type: def.type,
    version: Number.isInteger(def.version) ? def.version : 1,
    label: def.label || def.type,
    icon: def.icon || null,
    component: def.component || null,
    editor: def.editor || null,
    defaults: typeof def.defaults === 'function' ? def.defaults : () => ({}),
    container: Boolean(def.container),
    containerSlots: def.containerSlots ? [...def.containerSlots] : [],
  }
  registry.set(entry.type, entry)
  return entry
}

/** @returns {object|null} the definition for `type`, or null if unknown. */
export function getBlock(type) {
  return registry.get(type) || null
}

/** @returns {boolean} whether `type` is a registered block. */
export function hasBlock(type) {
  return registry.has(type)
}

/** @returns {object[]} all registered definitions (registration order). */
export function listBlocks() {
  return [...registry.values()]
}

/**
 * Generate a stable block id. Called once when a block is added to the canvas;
 * never derived from array position, so a reorder keeps ids intact (they are the
 * React key and the future revision-history join point).
 * @returns {string}
 */
export function makeBlockId() {
  const rand = Math.random().toString(36).slice(2, 8).toUpperCase()
  return `b_${rand}`
}
