"use client";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { memo, useState, useCallback, useMemo } from "react";
import { cn } from "@stigmer/theme";
import { TASK_NAME_PATTERN, TASK_NAME_PATTERN_ERROR } from "./canvas-constants.js";
const TIMEOUT_POLICY_OPTIONS = [
    { value: "HUMAN_INPUT_TIMEOUT_FAIL", label: "Fail — task errors on timeout" },
    { value: "HUMAN_INPUT_TIMEOUT_APPROVE", label: "Auto-approve — proceed as approved" },
    { value: "HUMAN_INPUT_TIMEOUT_DENY", label: "Auto-deny — proceed as denied" },
    { value: "HUMAN_INPUT_TIMEOUT_ESCALATE", label: "Escalate — branch to escalation task" },
];
const TIMEOUT_UNITS = [
    { value: 1, label: "seconds" },
    { value: 60, label: "minutes" },
    { value: 3600, label: "hours" },
    { value: 86400, label: "days" },
];
/**
 * Specialized inspector editor for `human_input` task nodes.
 *
 * Organized into collapsible sections: Prompt, Outcomes, Form Fields,
 * Timeout, Approvers, and Notification Channels. Outcome routing uses
 * name-based handle IDs (`outcome_{name}`) per AD-T15-B4.
 *
 * @since T15 Batch 4 (Specialized Task Editors)
 */
export const ApprovalFormBuilder = memo(function ApprovalFormBuilder({ nodeId, config, edges, allTaskNames, onUpdateConfig, onUpdateBranchRouting, onMigrateBranchHandle, onRemoveBranchEdges, }) {
    const cfg = config;
    const routingMap = useMemo(() => {
        const map = new Map();
        for (const edge of edges) {
            if (edge.source === nodeId && edge.sourceHandle?.startsWith("outcome_")) {
                map.set(edge.sourceHandle, edge.target);
            }
        }
        return map;
    }, [nodeId, edges]);
    return (_jsxs("div", { className: "flex flex-col", children: [_jsx(PromptSection, { prompt: typeof cfg.prompt === "string" ? cfg.prompt : "", onUpdate: onUpdateConfig }), _jsx(OutcomesSection, { config: cfg, routingMap: routingMap, allTaskNames: allTaskNames, onUpdateConfig: onUpdateConfig, onUpdateBranchRouting: onUpdateBranchRouting, onMigrateBranchHandle: onMigrateBranchHandle, onRemoveBranchEdges: onRemoveBranchEdges }), _jsx(FormSchemaSection, { formSchema: cfg.form_schema, onUpdateConfig: onUpdateConfig }), _jsx(TimeoutSection, { timeout: typeof cfg.timeout === "number" ? cfg.timeout : 0, onTimeout: typeof cfg.on_timeout === "string" ? cfg.on_timeout : "", escalationTask: typeof cfg.escalation_task === "string" ? cfg.escalation_task : "", allTaskNames: allTaskNames, onUpdateConfig: onUpdateConfig }), _jsx(StringListSection, { title: "Approvers", fieldPath: "approvers", values: extractStringList(cfg.approvers), placeholder: 'e.g., user:jane@acme.com, team:engineering-leads', onUpdateConfig: onUpdateConfig }), _jsx(StringListSection, { title: "Notification Channels", fieldPath: "notification_channels", values: extractStringList(cfg.notification_channels), placeholder: 'e.g., slack:#approvals, email:ops@acme.com', onUpdateConfig: onUpdateConfig })] }));
});
// ---------------------------------------------------------------------------
// PromptSection
// ---------------------------------------------------------------------------
function PromptSection({ prompt, onUpdate, }) {
    return (_jsx(CollapsibleSection, { title: "Prompt", defaultOpen: true, children: _jsx("textarea", { value: prompt, onChange: (e) => onUpdate("prompt", e.target.value || undefined), placeholder: "${ $context.ticket.id } needs approval \u2014 review and decide.", rows: 3, className: cn(inputClass, "resize-y font-mono"), "aria-label": "Prompt message" }) }));
}
// ---------------------------------------------------------------------------
// OutcomesSection
// ---------------------------------------------------------------------------
function OutcomesSection({ config, routingMap, allTaskNames, onUpdateConfig, onUpdateBranchRouting, onMigrateBranchHandle, onRemoveBranchEdges, }) {
    const outcomes = extractOutcomes(config);
    const commitOutcomes = useCallback((updated) => {
        onUpdateConfig("outcomes", updated.length === 0
            ? undefined
            : updated.map((o) => ({
                name: o.name,
                ...(o.label && { label: o.label }),
                ...(o.then && { then: o.then }),
            })));
    }, [onUpdateConfig]);
    const handleAdd = useCallback(() => {
        const existing = new Set(outcomes.map((o) => o.name));
        let n = outcomes.length + 1;
        while (existing.has(`outcome_${n}`))
            n++;
        commitOutcomes([...outcomes, { name: `outcome_${n}`, label: "", then: "" }]);
    }, [outcomes, commitOutcomes]);
    const handleRemove = useCallback((idx) => {
        const removed = outcomes[idx];
        onRemoveBranchEdges(`outcome_${removed.name}`);
        commitOutcomes(outcomes.filter((_, i) => i !== idx));
    }, [outcomes, commitOutcomes, onRemoveBranchEdges]);
    const handleMove = useCallback((idx, direction) => {
        const targetIdx = idx + direction;
        if (targetIdx < 0 || targetIdx >= outcomes.length)
            return;
        const updated = [...outcomes];
        [updated[idx], updated[targetIdx]] = [updated[targetIdx], updated[idx]];
        commitOutcomes(updated);
    }, [outcomes, commitOutcomes]);
    const handleNameChange = useCallback((idx, newName) => {
        const oldName = outcomes[idx].name;
        if (oldName === newName)
            return;
        const updated = [...outcomes];
        updated[idx] = { ...updated[idx], name: newName };
        commitOutcomes(updated);
        if (oldName) {
            onMigrateBranchHandle(`outcome_${oldName}`, `outcome_${newName}`);
        }
    }, [outcomes, commitOutcomes, onMigrateBranchHandle]);
    const handleLabelChange = useCallback((idx, label) => {
        const updated = [...outcomes];
        updated[idx] = { ...updated[idx], label };
        commitOutcomes(updated);
    }, [outcomes, commitOutcomes]);
    const handleThenChange = useCallback((idx, targetTask) => {
        const outcomeName = outcomes[idx].name;
        onUpdateBranchRouting(`outcome_${outcomeName}`, targetTask || undefined);
    }, [outcomes, onUpdateBranchRouting]);
    const [dragIdx, setDragIdx] = useState(null);
    const [dropIdx, setDropIdx] = useState(null);
    const handleDragStart = useCallback((idx) => { setDragIdx(idx); }, []);
    const handleDragOver = useCallback((idx) => { setDropIdx(idx); }, []);
    const handleDrop = useCallback(() => {
        if (dragIdx != null && dropIdx != null && dragIdx !== dropIdx) {
            const updated = [...outcomes];
            const [moved] = updated.splice(dragIdx, 1);
            updated.splice(dropIdx, 0, moved);
            commitOutcomes(updated);
        }
        setDragIdx(null);
        setDropIdx(null);
    }, [dragIdx, dropIdx, outcomes, commitOutcomes]);
    const handleDragEnd = useCallback(() => { setDragIdx(null); setDropIdx(null); }, []);
    return (_jsxs(CollapsibleSection, { title: "Outcomes", children: [outcomes.length === 0 && (_jsx("p", { className: "py-1 text-[11px] text-[var(--stgm-muted-foreground,#737373)]", children: "No custom outcomes. Default: binary Approve / Deny." })), _jsx("div", { className: "flex flex-col gap-2", children: outcomes.map((o, idx) => {
                    const routeTarget = routingMap.get(`outcome_${o.name}`) ?? "";
                    return (_jsx(OutcomeEntry, { outcome: o, index: idx, total: outcomes.length, routeTarget: routeTarget, allTaskNames: allTaskNames, allOutcomeNames: outcomes.map((x) => x.name), onNameChange: (name) => handleNameChange(idx, name), onLabelChange: (label) => handleLabelChange(idx, label), onThenChange: (then) => handleThenChange(idx, then), onMoveUp: () => handleMove(idx, -1), onMoveDown: () => handleMove(idx, 1), onRemove: () => handleRemove(idx), isDragOver: dropIdx === idx && dragIdx !== idx, onDragStart: () => handleDragStart(idx), onDragOver: () => handleDragOver(idx), onDrop: handleDrop, onDragEnd: handleDragEnd }, `${o.name}_${idx}`));
                }) }), _jsx("button", { type: "button", onClick: handleAdd, className: "mt-1 self-start text-[11px] font-medium text-[var(--stgm-primary,#6366f1)] hover:underline", children: "+ Add outcome" })] }));
}
function OutcomeEntry({ outcome, index, total, routeTarget, allTaskNames, allOutcomeNames, onNameChange, onLabelChange, onThenChange, onMoveUp, onMoveDown, onRemove, isDragOver, onDragStart, onDragOver, onDrop, onDragEnd, }) {
    const [editingName, setEditingName] = useState(outcome.name);
    const [nameError, setNameError] = useState(null);
    const validateAndCommit = useCallback(() => {
        const trimmed = editingName.trim();
        if (!trimmed) {
            setNameError("Name required");
            return;
        }
        if (!TASK_NAME_PATTERN.test(trimmed)) {
            setNameError(TASK_NAME_PATTERN_ERROR);
            return;
        }
        if (allOutcomeNames.some((n, i) => i !== index && n === trimmed)) {
            setNameError("Duplicate name");
            return;
        }
        setNameError(null);
        onNameChange(trimmed);
    }, [editingName, allOutcomeNames, index, onNameChange]);
    const handleDragOverEvent = useCallback((e) => { e.preventDefault(); onDragOver(); }, [onDragOver]);
    return (_jsxs("div", { onDragOver: handleDragOverEvent, onDrop: onDrop, className: cn("flex flex-col gap-1 rounded-md border border-[var(--stgm-border,#e5e5e5)] p-2 transition-[border-color]", isDragOver && "border-[var(--stgm-primary,#6366f1)]"), children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(DragGrip, { onDragStart: onDragStart, onDragEnd: onDragEnd }), _jsx("input", { type: "text", value: editingName, onChange: (e) => { setEditingName(e.target.value); setNameError(null); }, onBlur: validateAndCommit, onKeyDown: (e) => { if (e.key === "Enter")
                            validateAndCommit(); }, placeholder: "outcome_name", className: "min-w-0 flex-1 rounded border border-[var(--stgm-border,#d4d4d8)] bg-[var(--stgm-background,#fff)] px-1.5 py-1 text-xs font-medium text-[var(--stgm-foreground,#1a1a2e)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]", "aria-label": `Outcome ${index + 1} name` }), _jsxs("div", { className: "flex shrink-0 items-center", children: [_jsx(ArrowButton, { direction: "up", disabled: index === 0, onClick: onMoveUp }), _jsx(ArrowButton, { direction: "down", disabled: index === total - 1, onClick: onMoveDown }), _jsx("button", { type: "button", onClick: onRemove, className: "ml-0.5 text-[10px] text-[var(--stgm-destructive,#ef4444)] hover:underline", "aria-label": `Remove outcome ${outcome.name}`, children: "\u2715" })] })] }), nameError && _jsx("span", { className: "text-[10px] text-[var(--stgm-destructive,#ef4444)]", children: nameError }), _jsx("input", { type: "text", value: outcome.label, onChange: (e) => onLabelChange(e.target.value), placeholder: capitalize(outcome.name), className: cn(smallInputClass), "aria-label": `Label for outcome ${outcome.name}` }), _jsxs("select", { value: routeTarget, onChange: (e) => onThenChange(e.target.value), className: cn(smallInputClass), "aria-label": `Target task for outcome ${outcome.name}`, children: [_jsx("option", { value: "", children: "\u2014 Continue (next task) \u2014" }), allTaskNames.map((name) => (_jsx("option", { value: name, children: name }, name)))] })] }));
}
// ---------------------------------------------------------------------------
// FormSchemaSection
// ---------------------------------------------------------------------------
function FormSchemaSection({ formSchema, onUpdateConfig, }) {
    const [rawMode, setRawMode] = useState(false);
    const fields = useMemo(() => schemaToFields(formSchema), [formSchema]);
    const commitFields = useCallback((updated) => {
        onUpdateConfig("form_schema", fieldsToSchema(updated));
    }, [onUpdateConfig]);
    const handleAdd = useCallback(() => {
        const existing = new Set(fields.map((f) => f.name));
        let n = fields.length + 1;
        while (existing.has(`field_${n}`))
            n++;
        commitFields([...fields, { name: `field_${n}`, type: "string", required: false, description: "", enumValues: "" }]);
    }, [fields, commitFields]);
    const handleRemove = useCallback((idx) => commitFields(fields.filter((_, i) => i !== idx)), [fields, commitFields]);
    const handleUpdate = useCallback((idx, patch) => {
        const updated = [...fields];
        updated[idx] = { ...updated[idx], ...patch };
        commitFields(updated);
    }, [fields, commitFields]);
    const handleRawChange = useCallback((rawJson) => {
        try {
            const parsed = JSON.parse(rawJson);
            onUpdateConfig("form_schema", parsed);
        }
        catch { /* ignore invalid JSON while typing */ }
    }, [onUpdateConfig]);
    return (_jsxs(CollapsibleSection, { title: "Form Fields", children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("span", { className: "text-[10px] text-[var(--stgm-muted-foreground,#737373)]", children: rawMode ? "Raw JSON Schema" : "Visual builder" }), _jsx("button", { type: "button", onClick: () => setRawMode(!rawMode), className: "text-[10px] text-[var(--stgm-primary,#6366f1)] hover:underline", children: rawMode ? "Visual" : "Raw JSON" })] }), rawMode ? (_jsx("textarea", { value: formSchema != null ? JSON.stringify(formSchema, null, 2) : "", onChange: (e) => handleRawChange(e.target.value), rows: 8, className: cn(inputClass, "resize-y font-mono text-[11px]"), placeholder: '{ "type": "object", "properties": { ... } }' })) : (_jsxs(_Fragment, { children: [fields.length === 0 && (_jsx("p", { className: "py-1 text-[11px] text-[var(--stgm-muted-foreground,#737373)]", children: "No form fields. Reviewer sees only outcome buttons." })), _jsx("div", { className: "flex flex-col gap-1.5", children: fields.map((field, idx) => (_jsx(FormFieldRow, { field: field, index: idx, onUpdate: (patch) => handleUpdate(idx, patch), onRemove: () => handleRemove(idx) }, `${field.name}_${idx}`))) }), _jsx("button", { type: "button", onClick: handleAdd, className: "mt-1 self-start text-[11px] font-medium text-[var(--stgm-primary,#6366f1)] hover:underline", children: "+ Add field" })] }))] }));
}
function FormFieldRow({ field, index, onUpdate, onRemove, }) {
    return (_jsxs("div", { className: "flex flex-col gap-1 rounded border border-[var(--stgm-border,#e5e5e5)] p-1.5", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("input", { type: "text", value: field.name, onChange: (e) => onUpdate({ name: e.target.value }), placeholder: "field_name", className: "min-w-0 flex-1 rounded border border-[var(--stgm-border,#d4d4d8)] bg-[var(--stgm-background,#fff)] px-1 py-0.5 text-[11px] text-[var(--stgm-foreground,#1a1a2e)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]", "aria-label": `Field ${index + 1} name` }), _jsxs("select", { value: field.type, onChange: (e) => onUpdate({ type: e.target.value }), className: "rounded border border-[var(--stgm-border,#d4d4d8)] bg-[var(--stgm-background,#fff)] px-1 py-0.5 text-[11px] text-[var(--stgm-foreground,#1a1a2e)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]", "aria-label": `Type for field ${field.name}`, children: [_jsx("option", { value: "string", children: "string" }), _jsx("option", { value: "number", children: "number" }), _jsx("option", { value: "boolean", children: "boolean" }), _jsx("option", { value: "enum", children: "enum" })] }), _jsxs("label", { className: "flex shrink-0 cursor-pointer items-center gap-0.5 text-[10px] text-[var(--stgm-muted-foreground,#737373)]", children: [_jsx("input", { type: "checkbox", checked: field.required, onChange: (e) => onUpdate({ required: e.target.checked }), className: "h-3 w-3" }), "Req"] }), _jsx("button", { type: "button", onClick: onRemove, className: "text-[10px] text-[var(--stgm-destructive,#ef4444)] hover:underline", "aria-label": `Remove field ${field.name}`, children: "\u2715" })] }), _jsx("input", { type: "text", value: field.description, onChange: (e) => onUpdate({ description: e.target.value }), placeholder: "Description (optional)", className: "rounded border border-[var(--stgm-border,#d4d4d8)] bg-[var(--stgm-background,#fff)] px-1 py-0.5 text-[10px] text-[var(--stgm-foreground,#1a1a2e)] placeholder:text-[var(--stgm-muted-foreground,#a3a3a3)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]" }), field.type === "enum" && (_jsx("input", { type: "text", value: field.enumValues, onChange: (e) => onUpdate({ enumValues: e.target.value }), placeholder: "P1, P2, P3 (comma-separated)", className: "rounded border border-[var(--stgm-border,#d4d4d8)] bg-[var(--stgm-background,#fff)] px-1 py-0.5 text-[10px] font-mono text-[var(--stgm-foreground,#1a1a2e)] placeholder:text-[var(--stgm-muted-foreground,#a3a3a3)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]" }))] }));
}
// ---------------------------------------------------------------------------
// TimeoutSection
// ---------------------------------------------------------------------------
function TimeoutSection({ timeout, onTimeout, escalationTask, allTaskNames, onUpdateConfig, }) {
    const bestUnit = useMemo(() => {
        if (timeout <= 0)
            return 1;
        for (let i = TIMEOUT_UNITS.length - 1; i >= 0; i--) {
            if (timeout % TIMEOUT_UNITS[i].value === 0)
                return TIMEOUT_UNITS[i].value;
        }
        return 1;
    }, [timeout]);
    const [unit, setUnit] = useState(bestUnit);
    const displayValue = timeout > 0 ? Math.round(timeout / unit) : "";
    const handleValueChange = useCallback((e) => {
        const raw = e.target.value;
        if (raw === "") {
            onUpdateConfig("timeout", 0);
            return;
        }
        const n = parseInt(raw, 10);
        if (!isNaN(n) && n >= 0)
            onUpdateConfig("timeout", n * unit);
    }, [unit, onUpdateConfig]);
    const handleUnitChange = useCallback((e) => {
        const newUnit = Number(e.target.value);
        setUnit(newUnit);
        if (timeout > 0) {
            const currentValue = Math.round(timeout / unit);
            onUpdateConfig("timeout", currentValue * newUnit);
        }
    }, [timeout, unit, onUpdateConfig]);
    const isEscalate = onTimeout === "HUMAN_INPUT_TIMEOUT_ESCALATE";
    return (_jsxs(CollapsibleSection, { title: "Timeout", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("input", { type: "number", value: displayValue, onChange: handleValueChange, placeholder: "0", min: 0, className: cn(smallInputClass, "w-16"), "aria-label": "Timeout duration" }), _jsx("select", { value: unit, onChange: handleUnitChange, className: cn(smallInputClass, "w-20"), "aria-label": "Timeout unit", children: TIMEOUT_UNITS.map((u) => (_jsx("option", { value: u.value, children: u.label }, u.value))) })] }), timeout > 0 && (_jsxs("div", { className: "mt-1.5 flex flex-col gap-1", children: [_jsx("label", { className: "text-[10px] text-[var(--stgm-muted-foreground,#737373)]", children: "On timeout" }), _jsxs("select", { value: onTimeout, onChange: (e) => onUpdateConfig("on_timeout", e.target.value || undefined), className: cn(smallInputClass), "aria-label": "Timeout policy", children: [_jsx("option", { value: "", children: "\u2014 Default (fail) \u2014" }), TIMEOUT_POLICY_OPTIONS.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value)))] })] })), isEscalate && (_jsxs("div", { className: "mt-1.5 flex flex-col gap-1", children: [_jsx("label", { className: "text-[10px] text-[var(--stgm-muted-foreground,#737373)]", children: "Escalation task" }), _jsxs("select", { value: escalationTask, onChange: (e) => onUpdateConfig("escalation_task", e.target.value || undefined), className: cn(smallInputClass), "aria-label": "Escalation target task", children: [_jsx("option", { value: "", children: "\u2014 Select escalation task \u2014" }), allTaskNames.map((name) => (_jsx("option", { value: name, children: name }, name)))] })] }))] }));
}
// ---------------------------------------------------------------------------
// StringListSection
// ---------------------------------------------------------------------------
function StringListSection({ title, fieldPath, values, placeholder, onUpdateConfig, }) {
    const commit = useCallback((updated) => {
        onUpdateConfig(fieldPath, updated.length > 0 ? updated : undefined);
    }, [fieldPath, onUpdateConfig]);
    const handleAdd = useCallback(() => {
        commit([...values, ""]);
    }, [values, commit]);
    const handleRemove = useCallback((idx) => commit(values.filter((_, i) => i !== idx)), [values, commit]);
    const handleChange = useCallback((idx, val) => {
        const updated = [...values];
        updated[idx] = val;
        commit(updated);
    }, [values, commit]);
    return (_jsxs(CollapsibleSection, { title: title, children: [_jsx("div", { className: "flex flex-col gap-1", children: values.map((val, idx) => (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("input", { type: "text", value: val, onChange: (e) => handleChange(idx, e.target.value), placeholder: placeholder, className: cn(smallInputClass, "flex-1"), "aria-label": `${title} entry ${idx + 1}` }), _jsx("button", { type: "button", onClick: () => handleRemove(idx), className: "text-[10px] text-[var(--stgm-destructive,#ef4444)] hover:underline", "aria-label": `Remove ${title.toLowerCase()} entry ${idx + 1}`, children: "\u2715" })] }, idx))) }), _jsx("button", { type: "button", onClick: handleAdd, className: "mt-1 self-start text-[11px] font-medium text-[var(--stgm-primary,#6366f1)] hover:underline", children: "+ Add entry" })] }));
}
// ---------------------------------------------------------------------------
// CollapsibleSection
// ---------------------------------------------------------------------------
function CollapsibleSection({ title, defaultOpen = false, children, }) {
    const [open, setOpen] = useState(defaultOpen);
    return (_jsxs("div", { className: "border-b border-[var(--stgm-border,#e5e5e5)] last:border-b-0", children: [_jsxs("button", { type: "button", onClick: () => setOpen(!open), className: "flex w-full items-center gap-1.5 px-3 py-2 text-left text-xs font-semibold text-[var(--stgm-foreground,#1a1a2e)] hover:bg-[var(--stgm-muted,#f5f5f5)]", "aria-expanded": open, children: [_jsx("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: cn("transition-transform", open && "rotate-90"), children: _jsx("path", { d: "M6 4l4 4-4 4" }) }), title] }), open && _jsx("div", { className: "flex flex-col gap-1.5 px-3 pb-3", children: children })] }));
}
// ---------------------------------------------------------------------------
// DragGrip
// ---------------------------------------------------------------------------
function DragGrip({ onDragStart, onDragEnd, }) {
    return (_jsx("div", { draggable: true, onDragStart: onDragStart, onDragEnd: onDragEnd, className: "flex shrink-0 cursor-grab items-center text-[var(--stgm-muted-foreground,#a3a3a3)] hover:text-[var(--stgm-foreground,#1a1a2e)] active:cursor-grabbing", "aria-label": "Drag to reorder", children: _jsxs("svg", { width: "8", height: "14", viewBox: "0 0 8 14", fill: "currentColor", children: [_jsx("circle", { cx: "2", cy: "2", r: "1" }), _jsx("circle", { cx: "6", cy: "2", r: "1" }), _jsx("circle", { cx: "2", cy: "7", r: "1" }), _jsx("circle", { cx: "6", cy: "7", r: "1" }), _jsx("circle", { cx: "2", cy: "12", r: "1" }), _jsx("circle", { cx: "6", cy: "12", r: "1" })] }) }));
}
// ---------------------------------------------------------------------------
// ArrowButton (shared with BranchConditionBuilder pattern)
// ---------------------------------------------------------------------------
function ArrowButton({ direction, disabled, onClick, }) {
    return (_jsx("button", { type: "button", onClick: onClick, disabled: disabled, className: "px-0.5 py-0.5 text-[var(--stgm-muted-foreground,#737373)] hover:text-[var(--stgm-foreground,#1a1a2e)] disabled:opacity-30", "aria-label": `Move ${direction}`, children: _jsx("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: direction === "up" ? _jsx("path", { d: "M4 10l4-4 4 4" }) : _jsx("path", { d: "M4 6l4 4 4-4" }) }) }));
}
// ---------------------------------------------------------------------------
// Shared styles
// ---------------------------------------------------------------------------
const inputClass = "w-full rounded-md border border-[var(--stgm-border,#d4d4d8)] bg-[var(--stgm-background,#fff)] px-2 py-1.5 text-xs text-[var(--stgm-foreground,#1a1a2e)] placeholder:text-[var(--stgm-muted-foreground,#a3a3a3)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]";
const smallInputClass = "w-full rounded border border-[var(--stgm-border,#d4d4d8)] bg-[var(--stgm-background,#fff)] px-1.5 py-1 text-xs text-[var(--stgm-foreground,#1a1a2e)] placeholder:text-[var(--stgm-muted-foreground,#a3a3a3)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]";
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function extractOutcomes(config) {
    const raw = config.outcomes;
    if (!Array.isArray(raw))
        return [];
    return raw
        .filter((o) => o != null && typeof o === "object")
        .map((o) => ({
        name: typeof o.name === "string" ? o.name : "",
        label: typeof o.label === "string" ? o.label : "",
        then: typeof o.then === "string" ? o.then : "",
    }));
}
function extractStringList(value) {
    if (!Array.isArray(value))
        return [];
    return value.filter((v) => typeof v === "string");
}
function capitalize(str) {
    return str.replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}
function schemaToFields(schema) {
    if (!schema || typeof schema !== "object" || Array.isArray(schema))
        return [];
    const obj = schema;
    const properties = obj.properties;
    if (!properties || typeof properties !== "object" || Array.isArray(properties))
        return [];
    const requiredSet = new Set(Array.isArray(obj.required) ? obj.required.filter((r) => typeof r === "string") : []);
    return Object.entries(properties)
        .filter(([, v]) => v && typeof v === "object" && !Array.isArray(v))
        .map(([name, v]) => {
        const prop = v;
        const hasEnum = Array.isArray(prop.enum);
        let type = "string";
        if (hasEnum) {
            type = "enum";
        }
        else if (prop.type === "number" || prop.type === "integer") {
            type = "number";
        }
        else if (prop.type === "boolean") {
            type = "boolean";
        }
        return {
            name,
            type,
            required: requiredSet.has(name),
            description: typeof prop.description === "string" ? prop.description : "",
            enumValues: hasEnum ? prop.enum.map(String).join(", ") : "",
        };
    });
}
function fieldsToSchema(fields) {
    if (fields.length === 0)
        return undefined;
    const properties = {};
    const required = [];
    for (const field of fields) {
        if (!field.name.trim())
            continue;
        const prop = {};
        if (field.type === "enum") {
            prop.type = "string";
            const vals = field.enumValues.split(",").map((v) => v.trim()).filter(Boolean);
            if (vals.length > 0)
                prop.enum = vals;
        }
        else if (field.type === "number") {
            prop.type = "number";
        }
        else if (field.type === "boolean") {
            prop.type = "boolean";
        }
        else {
            prop.type = "string";
        }
        if (field.description)
            prop.description = field.description;
        if (field.required)
            required.push(field.name);
        properties[field.name] = prop;
    }
    return {
        type: "object",
        properties,
        ...(required.length > 0 && { required }),
    };
}
//# sourceMappingURL=ApprovalFormBuilder.js.map