'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
 * Recursive input dispatcher for component-block props. Given a
 * {@link PropSpec} and the currently stored value, renders the correct
 * editor:
 *
 * | PropType.kind         | Editor                                         |
 * | --------------------- | ---------------------------------------------- |
 * | `string`              | single-line text input                         |
 * | `number`              | native number input                            |
 * | `boolean`             | switch (ToggleField look)                      |
 * | `enum`                | select with the literal values                 |
 * | `literal`             | readonly display (it's the only allowed value) |
 * | `array`               | add/remove list of recursive PropInputs        |
 * | `object`              | bordered group of recursive PropInputs         |
 * | `union` (discriminated) | variant picker + recursive object form       |
 * | `union` (other)       | JSON textarea + hint                           |
 * | `reference`           | JSON textarea + "unresolved" hint              |
 * | `unknown`             | JSON textarea + warning                        |
 *
 * The component is intentionally small and self-contained — no calls
 * into cms-core; the parent {@link ComponentBlockField} runs validation
 * via `validateComponentBlockValue` and pipes per-prop errors back in
 * via the `errors` prop.
 */
import { detectDiscriminator, findVariant, } from '@actuate-media/component-blocks/discriminated-union';
import { defaultForType, parseEnumSelection, safeJsonStringify, switchUnionVariant, } from './component-block-helpers.js';
export { defaultForType };
export function PropInput({ prop, value, onChange, errors, path }) {
    const fullPath = path ?? prop.name;
    const safeErrors = errors ?? EMPTY_ERRORS;
    const error = safeErrors[fullPath];
    return (_jsxs("div", { className: "space-y-1", children: [_jsx(PropInputBody, { prop: prop, value: value, onChange: onChange, errors: safeErrors, path: fullPath }), prop.description && !error ? (_jsx("p", { className: "text-xs text-[var(--muted-foreground)]", children: prop.description })) : null, error ? _jsx("p", { className: "text-xs text-[var(--destructive)]", children: error }) : null] }));
}
const EMPTY_ERRORS = Object.freeze({});
function PropInputBody({ prop, value, onChange, errors, path }) {
    const type = prop.type;
    switch (type.kind) {
        case 'string':
            return _jsx(StringInput, { label: fieldLabel(prop), value: value, onChange: onChange });
        case 'number':
            return _jsx(NumberInputControl, { label: fieldLabel(prop), value: value, onChange: onChange });
        case 'boolean':
            return _jsx(BooleanInput, { label: fieldLabel(prop), value: value, onChange: onChange });
        case 'enum':
            return (_jsx(EnumInput, { label: fieldLabel(prop), options: type.values, value: value, onChange: onChange }));
        case 'literal':
            return _jsx(LiteralDisplay, { label: fieldLabel(prop), literal: type.value });
        case 'array':
            return (_jsx(ArrayInput, { label: fieldLabel(prop), itemType: type.itemType, itemPath: path, value: value, onChange: onChange, errors: errors }));
        case 'object':
            return (_jsx(ObjectInput, { label: fieldLabel(prop), fields: type.fields, value: value, onChange: onChange, errors: errors, path: path }));
        case 'union': {
            const detected = detectDiscriminator(type);
            if (detected) {
                return (_jsx(DiscriminatedUnionInput, { label: fieldLabel(prop), union: detected, value: value, onChange: onChange, errors: errors, path: path }));
            }
            return (_jsx(JsonFallback, { label: fieldLabel(prop), value: value, onChange: onChange, hint: fallbackHint(type) }));
        }
        case 'reference':
        case 'unknown':
        default:
            return (_jsx(JsonFallback, { label: fieldLabel(prop), value: value, onChange: onChange, hint: fallbackHint(type) }));
    }
}
function fieldLabel(prop) {
    return (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium", children: prop.name }), prop.required ? _jsx("span", { className: "ml-0.5 text-[var(--destructive)]", children: "*" }) : null] }));
}
function fallbackHint(type) {
    if (type.kind === 'reference') {
        return `Type '${type.targetType}' could not be resolved — paste a raw JSON value for now.`;
    }
    if (type.kind === 'union') {
        return 'Non-discriminated union — paste a raw JSON value (the form renders a picker for unions with a shared literal tag field like `kind`).';
    }
    return 'Unknown type — paste a raw JSON value.';
}
// ─── Primitive editors ───────────────────────────────────────────────
function StringInput({ label, value, onChange, }) {
    const stringVal = typeof value === 'string' ? value : '';
    return (_jsxs("label", { className: "block text-sm", children: [_jsx("div", { className: "mb-1", children: label }), _jsx("input", { type: "text", value: stringVal, onChange: (e) => onChange(e.target.value), className: "w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-[var(--ring)]" })] }));
}
function NumberInputControl({ label, value, onChange, }) {
    const numericVal = typeof value === 'number' ? value : '';
    return (_jsxs("label", { className: "block text-sm", children: [_jsx("div", { className: "mb-1", children: label }), _jsx("input", { type: "number", value: numericVal === '' ? '' : numericVal, onChange: (e) => {
                    const raw = e.target.value;
                    if (raw === '') {
                        onChange(undefined);
                        return;
                    }
                    const parsed = Number(raw);
                    onChange(Number.isNaN(parsed) ? raw : parsed);
                }, className: "w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-[var(--ring)]" })] }));
}
function BooleanInput({ label, value, onChange, }) {
    const boolVal = value === true;
    return (_jsxs("div", { className: "flex items-center justify-between text-sm", children: [_jsx("span", { children: label }), _jsx("button", { type: "button", role: "switch", "aria-checked": boolVal, onClick: () => onChange(!boolVal), className: `relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${boolVal ? 'bg-[var(--primary)]' : 'bg-[var(--muted)]'}`, children: _jsx("span", { className: `bg-card pointer-events-none inline-block h-5 w-5 rounded-full shadow-sm ring-0 transition-transform ${boolVal ? 'translate-x-5' : 'translate-x-0'}` }) })] }));
}
function EnumInput({ label, options, value, onChange, }) {
    const currentIdx = options.findIndex((o) => o === value);
    return (_jsxs("label", { className: "block text-sm", children: [_jsx("div", { className: "mb-1", children: label }), _jsxs("select", { value: currentIdx === -1 ? '' : String(currentIdx), onChange: (e) => {
                    onChange(parseEnumSelection(e.target.value, options));
                }, className: "w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-[var(--ring)]", children: [_jsx("option", { value: "", children: "Select\u2026" }), options.map((opt, idx) => (_jsx("option", { value: idx, children: String(opt) }, String(opt))))] })] }));
}
function LiteralDisplay({ label, literal, }) {
    return (_jsxs("div", { className: "text-sm", children: [_jsx("div", { className: "mb-1", children: label }), _jsxs("div", { className: "rounded-md border border-dashed border-[var(--border)] bg-[var(--muted)] px-3 py-2 text-xs text-[var(--muted-foreground)]", children: ["Fixed: ", _jsx("code", { children: String(literal) })] })] }));
}
// ─── Composite editors ───────────────────────────────────────────────
function ObjectInput({ label, fields, value, onChange, errors, path, }) {
    const obj = isPlainObject(value) ? value : {};
    return (_jsxs("fieldset", { className: "rounded-md border border-[var(--border)] bg-[var(--card)] p-3 text-sm", children: [_jsx("legend", { className: "px-1 text-xs tracking-wide text-[var(--muted-foreground)] uppercase", children: label }), _jsx("div", { className: "space-y-3", children: fields.map((field) => (_jsx(PropInput, { prop: field, value: obj[field.name], onChange: (next) => onChange({ ...obj, [field.name]: next }), errors: errors, path: `${path}.${field.name}` }, field.name))) })] }));
}
function ArrayInput({ label, itemType, itemPath, value, onChange, errors, }) {
    const arr = Array.isArray(value) ? value : [];
    return (_jsxs("div", { className: "text-sm", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between", children: [_jsx("span", { children: label }), _jsx("button", { type: "button", onClick: () => onChange([...arr, defaultForType(itemType)]), className: "rounded-md border border-[var(--border)] bg-[var(--input-background)] px-2 py-1 text-xs text-[var(--foreground)] hover:bg-[var(--accent)]", children: "+ Add" })] }), arr.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed border-[var(--border)] px-3 py-4 text-center text-xs text-[var(--muted-foreground)]", children: "No items yet" })) : (_jsx("ol", { className: "space-y-2", children: arr.map((item, idx) => (_jsxs("li", { className: "rounded-md border border-[var(--border)] bg-[var(--card)] p-3", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between text-xs text-[var(--muted-foreground)]", children: [_jsxs("span", { children: ["Item ", idx + 1] }), _jsx("button", { type: "button", onClick: () => onChange(arr.filter((_, i) => i !== idx)), className: "text-[var(--destructive)] hover:underline", children: "Remove" })] }), _jsx(PropInput, { prop: { name: `[${idx}]`, type: itemType, required: true }, value: item, onChange: (next) => onChange(arr.map((v, i) => (i === idx ? next : v))), errors: errors, path: `${itemPath}[${idx}]` })] }, idx))) }))] }));
}
function DiscriminatedUnionInput({ label, union, value, onChange, errors, path, }) {
    const currentVariant = findVariant(value, union);
    const obj = isPlainObject(value) ? value : {};
    function switchTo(variantIdx) {
        const variant = union.variants[variantIdx];
        if (!variant)
            return;
        onChange(switchUnionVariant(value, union, variant));
    }
    const currentIdx = currentVariant
        ? union.variants.findIndex((v) => v.value === currentVariant.value)
        : -1;
    return (_jsxs("fieldset", { className: "rounded-md border border-[var(--border)] bg-[var(--card)] p-3 text-sm", children: [_jsx("legend", { className: "px-1 text-xs tracking-wide text-[var(--muted-foreground)] uppercase", children: label }), _jsxs("div", { className: "space-y-3", children: [_jsxs("label", { className: "block text-sm", children: [_jsxs("div", { className: "mb-1", children: [_jsx("span", { className: "font-medium", children: union.field }), _jsx("span", { className: "ml-0.5 text-[var(--destructive)]", children: "*" }), _jsx("span", { className: "ml-2 text-xs text-[var(--muted-foreground)]", children: "(variant)" })] }), _jsxs("select", { value: currentIdx === -1 ? '' : String(currentIdx), onChange: (e) => {
                                    const idx = Number(e.target.value);
                                    if (Number.isInteger(idx) && idx >= 0 && idx < union.variants.length) {
                                        switchTo(idx);
                                    }
                                }, className: "w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-[var(--ring)]", children: [_jsx("option", { value: "", disabled: true, children: "Select a variant\u2026" }), union.variants.map((variant, idx) => (_jsx("option", { value: idx, children: String(variant.value) }, String(variant.value))))] })] }), currentVariant && currentVariant.remainingFields.length > 0 ? (_jsx("div", { className: "space-y-3", children: currentVariant.remainingFields.map((field) => (_jsx(PropInput, { prop: field, value: obj[field.name], onChange: (next) => onChange({ ...obj, [field.name]: next }), errors: errors, path: `${path}.${field.name}` }, field.name))) })) : null, !currentVariant ? (_jsx("p", { className: "text-xs text-[var(--muted-foreground)]", children: "Pick a variant to configure its fields." })) : null] })] }));
}
function JsonFallback({ label, value, onChange, hint, }) {
    // Treat both `undefined` and `null` as "empty" — `null` arrives as
    // the structural default for kinds we can't seed (union / reference /
    // unknown) and also from a JSON round-trip on `undefined`. Rendering
    // the literal string "null" would surface as broken UX.
    const text = value === undefined || value === null ? '' : safeJsonStringify(value);
    return (_jsxs("label", { className: "block text-sm", children: [_jsx("div", { className: "mb-1", children: label }), _jsx("textarea", { value: text, onChange: (e) => {
                    const raw = e.target.value;
                    if (raw.trim() === '') {
                        onChange(undefined);
                        return;
                    }
                    try {
                        onChange(JSON.parse(raw));
                    }
                    catch {
                        // Keep the raw string so the user can finish editing without
                        // losing focus; the validator will catch it on save.
                        onChange(raw);
                    }
                }, rows: 3, className: "w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 font-mono text-xs outline-none focus:ring-2 focus:ring-[var(--ring)]" }), _jsx("p", { className: "mt-1 text-xs text-[var(--muted-foreground)]", children: hint })] }));
}
// ─── Helpers ─────────────────────────────────────────────────────────
function isPlainObject(v) {
    return v !== null && typeof v === 'object' && !Array.isArray(v);
}
//# sourceMappingURL=PropInput.js.map