"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { memo, useState, useCallback } from "react";
import { cn } from "@stigmer/theme";
import { TASK_NAME_PATTERN, TASK_NAME_PATTERN_ERROR } from "./canvas-constants.js";
/**
 * Specialized inspector editor for `switch_case` task nodes.
 *
 * Renders an ordered list of conditional branches with name, condition
 * expression (`when`), and target task routing. Handles are name-based
 * (`case_{name}`) per AD-T15-B4, making reorder operations safe without
 * edge remapping.
 *
 * Edges are the source of truth for routing — the builder reads target
 * tasks from graph edges and writes routing changes via
 * `onUpdateBranchRouting`.
 *
 * @since T15 Batch 4 (Specialized Task Editors)
 */
export const BranchConditionBuilder = memo(function BranchConditionBuilder({ nodeId, config, edges, allTaskNames, onUpdateConfig, onUpdateBranchRouting, onMigrateBranchHandle, onRemoveBranchEdges, }) {
    const cases = extractCases(config);
    const [dragIdx, setDragIdx] = useState(null);
    const [dropIdx, setDropIdx] = useState(null);
    const routingMap = buildRoutingMap(nodeId, edges, "case_");
    const commitCases = useCallback((updated) => {
        onUpdateConfig("cases", updated.map((c) => ({
            name: c.name,
            ...(c.when && { when: c.when }),
            ...(c.then && { then: c.then }),
        })));
    }, [onUpdateConfig]);
    const handleAddCase = useCallback(() => {
        const existingNames = new Set(cases.map((c) => c.name));
        let n = cases.length + 1;
        while (existingNames.has(`case_${n}`))
            n++;
        const newCase = { name: `case_${n}`, when: "", then: "" };
        commitCases([...cases, newCase]);
    }, [cases, commitCases]);
    const handleRemoveCase = useCallback((idx) => {
        if (cases.length <= 1)
            return;
        const removed = cases[idx];
        onRemoveBranchEdges(`case_${removed.name}`);
        commitCases(cases.filter((_, i) => i !== idx));
    }, [cases, commitCases, onRemoveBranchEdges]);
    const handleMoveCase = useCallback((idx, direction) => {
        const targetIdx = idx + direction;
        if (targetIdx < 0 || targetIdx >= cases.length)
            return;
        const updated = [...cases];
        [updated[idx], updated[targetIdx]] = [updated[targetIdx], updated[idx]];
        commitCases(updated);
    }, [cases, commitCases]);
    const handleNameChange = useCallback((idx, newName) => {
        const oldName = cases[idx].name;
        if (oldName === newName)
            return;
        const updated = [...cases];
        updated[idx] = { ...updated[idx], name: newName };
        commitCases(updated);
        if (oldName) {
            onMigrateBranchHandle(`case_${oldName}`, `case_${newName}`);
        }
    }, [cases, commitCases, onMigrateBranchHandle]);
    const handleWhenChange = useCallback((idx, when) => {
        const updated = [...cases];
        updated[idx] = { ...updated[idx], when };
        commitCases(updated);
    }, [cases, commitCases]);
    const handleThenChange = useCallback((idx, targetTask) => {
        const caseName = cases[idx].name;
        onUpdateBranchRouting(`case_${caseName}`, targetTask || undefined);
    }, [cases, onUpdateBranchRouting]);
    const handleDragStart = useCallback((idx) => {
        setDragIdx(idx);
    }, []);
    const handleDragOver = useCallback((idx) => {
        setDropIdx(idx);
    }, []);
    const handleDrop = useCallback(() => {
        if (dragIdx != null && dropIdx != null && dragIdx !== dropIdx) {
            const updated = [...cases];
            const [moved] = updated.splice(dragIdx, 1);
            updated.splice(dropIdx, 0, moved);
            commitCases(updated);
        }
        setDragIdx(null);
        setDropIdx(null);
    }, [dragIdx, dropIdx, cases, commitCases]);
    const handleDragEnd = useCallback(() => {
        setDragIdx(null);
        setDropIdx(null);
    }, []);
    return (_jsxs("div", { className: "flex flex-col gap-2 px-3 pb-3", children: [cases.length === 0 && (_jsx("p", { className: "py-2 text-xs text-[var(--stgm-muted-foreground,#737373)]", children: "No cases defined. Add a case to start branching." })), cases.map((c, idx) => {
                const isDefault = !c.when && idx === cases.length - 1;
                const routeTarget = routingMap.get(`case_${c.name}`) ?? "";
                return (_jsx(CaseEntry, { caseDef: c, index: idx, total: cases.length, isDefault: isDefault, routeTarget: routeTarget, allTaskNames: allTaskNames, allCaseNames: cases.map((x) => x.name), onNameChange: (name) => handleNameChange(idx, name), onWhenChange: (when) => handleWhenChange(idx, when), onThenChange: (then) => handleThenChange(idx, then), onMoveUp: () => handleMoveCase(idx, -1), onMoveDown: () => handleMoveCase(idx, 1), onRemove: () => handleRemoveCase(idx), canRemove: cases.length > 1, isDragOver: dropIdx === idx && dragIdx !== idx, onDragStart: () => handleDragStart(idx), onDragOver: () => handleDragOver(idx), onDrop: handleDrop, onDragEnd: handleDragEnd }, `${c.name}_${idx}`));
            }), _jsx("button", { type: "button", onClick: handleAddCase, className: "self-start text-[11px] font-medium text-[var(--stgm-primary,#6366f1)] hover:underline", children: "+ Add case" })] }));
});
// ---------------------------------------------------------------------------
// CaseEntry
// ---------------------------------------------------------------------------
function CaseEntry({ caseDef, index, total, isDefault, routeTarget, allTaskNames, allCaseNames, onNameChange, onWhenChange, onThenChange, onMoveUp, onMoveDown, onRemove, canRemove, isDragOver, onDragStart, onDragOver, onDrop, onDragEnd, }) {
    const [nameError, setNameError] = useState(null);
    const [editingName, setEditingName] = useState(caseDef.name);
    const validateAndCommitName = useCallback(() => {
        const trimmed = editingName.trim();
        if (!trimmed) {
            setNameError("Name required");
            return;
        }
        if (!TASK_NAME_PATTERN.test(trimmed)) {
            setNameError(TASK_NAME_PATTERN_ERROR);
            return;
        }
        const isDuplicate = allCaseNames.some((n, i) => i !== index && n === trimmed);
        if (isDuplicate) {
            setNameError("Duplicate name");
            return;
        }
        setNameError(null);
        onNameChange(trimmed);
    }, [editingName, allCaseNames, index, onNameChange]);
    const handleDragOverEvent = useCallback((e) => {
        e.preventDefault();
        onDragOver();
    }, [onDragOver]);
    return (_jsxs("div", { onDragOver: handleDragOverEvent, onDrop: onDrop, className: cn("flex flex-col gap-1.5 rounded-md border p-2 transition-[border-color]", isDefault
            ? "border-[var(--stgm-chart-amber,#f59e0b)]/30 bg-[var(--stgm-chart-amber,#f59e0b)]/5"
            : "border-[var(--stgm-border,#e5e5e5)]", 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: validateAndCommitName, onKeyDown: (e) => { if (e.key === "Enter")
                            validateAndCommitName(); }, placeholder: "case_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": `Case ${index + 1} name` }), isDefault && (_jsx("span", { className: "shrink-0 rounded bg-[var(--stgm-chart-amber,#f59e0b)]/15 px-1 py-px text-[9px] font-medium text-[var(--stgm-chart-amber,#f59e0b)]", children: "default" })), _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, disabled: !canRemove, className: "ml-0.5 text-[10px] text-[var(--stgm-destructive,#ef4444)] hover:underline disabled:opacity-30", "aria-label": `Remove case ${caseDef.name}`, children: "\u2715" })] })] }), nameError && (_jsx("span", { className: "text-[10px] text-[var(--stgm-destructive,#ef4444)]", children: nameError })), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("label", { className: "text-[10px] text-[var(--stgm-muted-foreground,#737373)]", children: "Condition" }), _jsx("textarea", { value: caseDef.when, onChange: (e) => onWhenChange(e.target.value), placeholder: isDefault ? "(no condition — default case)" : "${ $context.value > 5 }", rows: 2, className: "w-full resize-y rounded border border-[var(--stgm-border,#d4d4d8)] bg-[var(--stgm-background,#fff)] px-1.5 py-1 font-mono text-[11px] text-[var(--stgm-foreground,#1a1a2e)] placeholder:text-[var(--stgm-muted-foreground,#a3a3a3)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]", "aria-label": `Condition for case ${caseDef.name}` })] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("label", { className: "text-[10px] text-[var(--stgm-muted-foreground,#737373)]", children: "Then go to" }), _jsxs("select", { value: routeTarget, onChange: (e) => onThenChange(e.target.value), className: "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)] focus:outline-none focus:ring-1 focus:ring-[var(--stgm-ring,#3b82f6)]", "aria-label": `Target task for case ${caseDef.name}`, children: [_jsx("option", { value: "", children: "\u2014 Not connected \u2014" }), allTaskNames.map((name) => (_jsx("option", { value: name, children: name }, name)))] })] })] }));
}
// ---------------------------------------------------------------------------
// 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
// ---------------------------------------------------------------------------
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" }) }) }));
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function extractCases(config) {
    const raw = config.cases;
    if (!Array.isArray(raw))
        return [];
    return raw
        .filter((c) => c != null && typeof c === "object")
        .map((c) => ({
        name: typeof c.name === "string" ? c.name : "",
        when: typeof c.when === "string" ? c.when : "",
        then: typeof c.then === "string" ? c.then : "",
    }));
}
function buildRoutingMap(nodeId, edges, prefix) {
    const map = new Map();
    for (const edge of edges) {
        if (edge.source === nodeId && edge.sourceHandle?.startsWith(prefix)) {
            map.set(edge.sourceHandle, edge.target);
        }
    }
    return map;
}
//# sourceMappingURL=BranchConditionBuilder.js.map