/**
 * Field-type registry — the edition boundary for the admin builder
 * (docs/wporg-free-runtime-separation.md, Phase 7 / §8.2).
 *
 * Each edition entrypoint registers its field types BEFORE importing the
 * shared app (src/admin/main.js):
 *
 *   admin-free/main.js  -> registers the Free types only
 *   admin-pro/main.js   -> registers Free + Pro types
 *
 * The shared shell (palette, canvas, drawer, preview, store) consults this
 * registry instead of hard-coding type ids, so the Free bundle genuinely
 * contains no Pro editor code, markup, icons, or type identifiers.
 *
 * A type definition:
 *   {
 *     type,                // canonical id ('text', 'rating', …)
 *     label, description,  // palette copy
 *     default: {},         // palette insert defaults (as before, in constants/fields.js)
 *     capability,          // Pro types only — canonical capability key
 *
 *     // Behavior flags consulted by the shared shell. Defaults are the plain
 *     // text-input semantics; list only the exceptions.
 *     static: false,             // no name/required/validation (button, heading, …)
 *     supportsRequired: true,
 *     supportsPlaceholder: true,
 *     supportsOptions: false,    // shows the shared options textarea (select/radio/…)
 *     supportsAccept: false,     // shows the shared file-accept block (file/multi_file)
 *     grid: true,                // participates in the column grid
 *     hideLabelInput: false,     // drawer hides the label input entirely
 *
 *     icon,                // resolved SVG URL for palette + canvas
 *
 *     // Drawer panel for type-specific controls (Pro panels live under
 *     // src/admin-pro/fields/). placement 'basics' renders after the label
 *     // input; 'body' renders after the shared accept/options region.
 *     editor: Component | undefined,
 *     editorPlacement: 'basics' | 'body',
 *
 *     // Drawer data hooks (replace the per-type branches that used to live in
 *     // FieldEditorDrawer.vue):
 *     localDefaults: {},              // drawer-local keys this type edits (reset on field switch)
 *     hydrate(field, local),          // seed drawer state from the stored field
 *     commitProps(local, updated),    // write drawer state back onto the update payload
 *
 *     // Builder-preview partial (FormPreviewSurface renders it when present).
 *     preview: Component | undefined,
 *
 *     // Store hooks (replace per-type branches in formStore.js):
 *     seedDefaults(field, def),       // extra props when inserted from the palette
 *     applyAiProps(src, built),       // extra props accepted from the AI assistant
 *     mapSaveProps(src, mapped),      // extra props carried through save serialization
 *   }
 *
 * Unknown types (a Pro field opened in the Free builder) are PRESERVED, never
 * edited: the drawer shows an inert placeholder and the store serializes the
 * stored field verbatim (see §5.4 "Pro field preserved but inactive").
 */

const defs = new Map();

export function registerFieldType(def) {
    if (!def || typeof def.type !== "string" || def.type === "") {
        return;
    }
    defs.set(def.type, def);
}

export function registerFieldTypes(list) {
    (list || []).forEach(registerFieldType);
}

/** @returns {object|null} the definition, or null for unknown (preserved) types. */
export function fieldTypeDef(type) {
    return defs.get(type) || null;
}

export function isKnownFieldType(type) {
    return defs.has(type);
}

/** Registration-ordered list — palette order follows it. */
export function fieldTypeList() {
    return [...defs.values()];
}

/** Behavior-flag helpers with plain-input defaults for the shared shell. */
export function typeFlag(type, flag, fallbackForUnknown = false) {
    const def = defs.get(type);
    if (!def) {
        return fallbackForUnknown;
    }
    switch (flag) {
        case "static":
            return def.static === true;
        case "supportsRequired":
            return def.supportsRequired !== false;
        case "supportsPlaceholder":
            return def.supportsPlaceholder !== false;
        case "supportsOptions":
            return def.supportsOptions === true;
        case "supportsAccept":
            return def.supportsAccept === true;
        case "grid":
            return def.grid !== false;
        case "hideLabelInput":
            return def.hideLabelInput === true;
        case "logicPeer":
            // Can this field's value gate another field's visibility?
            return def.logicPeer !== false;
        default:
            return false;
    }
}
