'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * Fields tab of the Form Schema drawer. Renders the form's field list with
 * drag-to-reorder (dnd-kit, keyboard-accessible) plus an inline editor for the
 * selected field. The parent owns the `fields` array and persistence; this
 * panel is a controlled editor that calls `onChange` with the next array.
 */
import { DndContext, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors, } from '@dnd-kit/core';
import { SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { ChevronDown, GripVertical, Plus, Trash2 } from 'lucide-react';
import { Toggle } from '../ui/Toggle.js';
import { useId, useState } from 'react';
import { FieldTypeBadge, FormsEmptyState } from './primitives.js';
const FIELD_TYPES = [
    { value: 'text', label: 'Text' },
    { value: 'email', label: 'Email' },
    { value: 'phone', label: 'Phone' },
    { value: 'textarea', label: 'Textarea' },
    { value: 'select', label: 'Select' },
    { value: 'multiselect', label: 'Multi-select' },
    { value: 'radio', label: 'Radio' },
    { value: 'checkbox', label: 'Checkbox' },
    { value: 'date', label: 'Date' },
    { value: 'number', label: 'Number' },
    { value: 'url', label: 'URL' },
    { value: 'consent', label: 'Consent' },
    { value: 'file', label: 'File upload' },
    { value: 'hidden', label: 'Hidden' },
    { value: 'richtext', label: 'Content block' },
    { value: 'divider', label: 'Divider / heading' },
];
const OPTION_TYPES = ['select', 'multiselect', 'radio'];
function slugifyKey(label) {
    return label
        .toLowerCase()
        .trim()
        .replace(/[^a-z0-9]+/g, '_')
        .replace(/^_+|_+$/g, '');
}
function makeId() {
    if (typeof crypto !== 'undefined' && 'randomUUID' in crypto)
        return crypto.randomUUID();
    return `f_${Math.random().toString(36).slice(2)}`;
}
export function FieldsPanel({ fields, onChange, hasSubmissions, }) {
    const [editingId, setEditingId] = useState(null);
    const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
    function handleDragEnd(event) {
        const { active, over } = event;
        if (!over || active.id === over.id)
            return;
        const ids = fields.map((f) => f.id);
        const from = ids.indexOf(String(active.id));
        const to = ids.indexOf(String(over.id));
        if (from === -1 || to === -1)
            return;
        const next = fields.slice();
        const [moved] = next.splice(from, 1);
        next.splice(to, 0, moved);
        onChange(next.map((f, i) => ({ ...f, sortOrder: i })));
    }
    function updateField(id, patch) {
        onChange(fields.map((f) => (f.id === id ? { ...f, ...patch } : f)));
    }
    function deleteField(id) {
        onChange(fields.filter((f) => f.id !== id));
        if (editingId === id)
            setEditingId(null);
    }
    function addField() {
        const id = makeId();
        const next = {
            id,
            label: 'New Field',
            key: `field_${fields.length + 1}`,
            type: 'text',
            required: false,
            sortOrder: fields.length,
        };
        onChange([...fields, next]);
        setEditingId(id);
    }
    return (_jsxs("div", { className: "space-y-3", children: [fields.length === 0 ? (_jsx(FormsEmptyState, { title: "No fields yet", description: "Add your first field to start building this form." })) : (_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: fields.map((f) => f.id), strategy: verticalListSortingStrategy, children: _jsx("ul", { className: "space-y-2", children: fields.map((field) => (_jsx(SortableFieldRow, { field: field, editing: editingId === field.id, hasSubmissions: hasSubmissions, onToggleEdit: () => setEditingId((cur) => (cur === field.id ? null : field.id)), onUpdate: (patch) => updateField(field.id, patch), onDelete: () => deleteField(field.id) }, field.id))) }) }) })), _jsxs("button", { type: "button", onClick: addField, className: "border-border text-foreground hover:bg-accent flex w-full items-center justify-center gap-2 rounded-lg border border-dashed px-3 py-2.5 text-sm font-medium transition-colors", children: [_jsx(Plus, { className: "h-4 w-4", "aria-hidden": true }), "Add Field"] })] }));
}
function SortableFieldRow({ field, editing, hasSubmissions, onToggleEdit, onUpdate, onDelete, }) {
    const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
        id: field.id,
    });
    const style = {
        transform: CSS.Transform.toString(transform),
        transition,
        zIndex: isDragging ? 10 : undefined,
    };
    const needsOptions = OPTION_TYPES.includes(field.type);
    return (_jsx("li", { ref: setNodeRef, style: style, children: _jsxs("div", { className: `border-border bg-card rounded-lg border ${isDragging ? 'shadow-md' : ''} ${editing ? 'ring-primary/30 ring-1' : ''}`, children: [_jsxs("div", { className: "flex items-center gap-2 px-2.5 py-2", children: [_jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring shrink-0 cursor-grab touch-none rounded focus-visible:ring-2 focus-visible:outline-none", "aria-label": `Drag to reorder ${field.label}`, ...attributes, ...listeners, children: _jsx(GripVertical, { className: "h-4 w-4", "aria-hidden": true }) }), _jsx("button", { type: "button", onClick: onToggleEdit, className: "flex min-w-0 flex-1 items-center gap-2 text-left", "aria-expanded": editing, children: _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "text-foreground block truncate text-sm font-medium", children: field.label || '(untitled)' }), _jsx("span", { className: "text-muted-foreground block truncate font-mono text-xs", children: field.key })] }) }), _jsx(FieldTypeBadge, { type: field.type }), field.required && (_jsx("span", { className: "bg-muted text-muted-foreground rounded px-1.5 py-0.5 text-[10px] font-medium uppercase", children: "Required" })), _jsx("button", { type: "button", onClick: onToggleEdit, className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring shrink-0 rounded p-1 focus-visible:ring-2 focus-visible:outline-none", "aria-label": `${editing ? 'Collapse' : 'Edit'} ${field.label}`, children: _jsx(ChevronDown, { className: `h-4 w-4 transition-transform ${editing ? '' : '-rotate-90'}`, "aria-hidden": true }) }), _jsx("button", { type: "button", onClick: onDelete, className: "text-muted-foreground hover:text-destructive focus-visible:ring-ring shrink-0 rounded p-1 focus-visible:ring-2 focus-visible:outline-none", "aria-label": `Delete ${field.label}`, children: _jsx(Trash2, { className: "h-4 w-4", "aria-hidden": true }) })] }), editing && (_jsx(FieldEditor, { field: field, hasSubmissions: hasSubmissions, needsOptions: needsOptions, onUpdate: onUpdate }))] }) }));
}
function FieldEditor({ field, hasSubmissions, needsOptions, onUpdate, }) {
    const reqId = useId();
    const optionsText = (field.options ?? []).map((o) => o.label).join('\n');
    return (_jsxs("div", { className: "border-border space-y-3 border-t px-3 py-3", children: [_jsxs("div", { className: "grid grid-cols-1 gap-3", children: [_jsx(Labeled, { label: "Label", children: _jsx("input", { type: "text", value: field.label, onChange: (e) => {
                                const label = e.target.value;
                                // Auto-derive the key from the label until the form has data and
                                // until the user has clearly customised the key.
                                const autoKey = slugifyKey(field.label);
                                const patch = { label };
                                if (!hasSubmissions && (field.key === autoKey || !field.key)) {
                                    patch.key = slugifyKey(label);
                                }
                                onUpdate(patch);
                            }, className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none" }) }), _jsx(Labeled, { label: "Key", hint: hasSubmissions ? 'Renaming affects existing entries & exports' : undefined, children: _jsx("input", { type: "text", value: field.key, onChange: (e) => onUpdate({ key: slugifyKey(e.target.value) }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 font-mono text-sm focus-visible:ring-2 focus-visible:outline-none" }) }), _jsx(Labeled, { label: "Type", children: _jsx("select", { value: field.type, onChange: (e) => onUpdate({ type: e.target.value }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none", children: FIELD_TYPES.map((t) => (_jsx("option", { value: t.value, children: t.label }, t.value))) }) }), _jsx(Labeled, { label: "Placeholder", children: _jsx("input", { type: "text", value: field.placeholder ?? '', onChange: (e) => onUpdate({ placeholder: e.target.value }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none" }) })] }), _jsx(Labeled, { label: "Help text", children: _jsx("input", { type: "text", value: field.helpText ?? '', onChange: (e) => onUpdate({ helpText: e.target.value }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none" }) }), needsOptions && (_jsx(Labeled, { label: "Options", hint: "One per line", children: _jsx("textarea", { rows: 3, value: optionsText, onChange: (e) => onUpdate({
                        options: e.target.value
                            .split('\n')
                            .map((line) => line.trim())
                            .filter(Boolean)
                            .map((label) => ({ label, value: slugifyKey(label) })),
                    }), className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none" }) })), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: reqId, className: "text-foreground text-sm font-medium", children: "Required" }), _jsx(Toggle, { id: reqId, checked: field.required, onCheckedChange: (v) => onUpdate({ required: v }), "aria-labelledby": reqId })] })] }));
}
function Labeled({ label, hint, children, }) {
    return (_jsxs("label", { className: "block", children: [_jsx("span", { className: "text-muted-foreground mb-1 block text-xs font-medium", children: label }), children, hint && _jsx("span", { className: "text-warning mt-1 block text-xs", children: hint })] }));
}
//# sourceMappingURL=FieldsPanel.js.map