"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { memo, useState, useCallback } from "react";
import { cn } from "@stigmer/theme";
const MULTILINE_FIELD_PATTERNS = /prompt|expression|body|template|query|script/i;
const MAX_RECURSION_DEPTH = 2;
/**
 * Schema-driven form generated from `TaskKindDescriptor.fields` and `fieldGroups`.
 *
 * Renders each field with the appropriate control based on its `TaskFieldType`:
 * text inputs, number inputs, toggles, selects, embedded YAML editors, and
 * list/map editors. Fields are organized into collapsible groups.
 *
 * Pure presentational — does not own state. Receives the current config
 * and reports changes via `onChange(fieldPath, value)`.
 *
 * @since T15 Batch 3 (Inspector + Edit Loop)
 */
export const TaskConfigForm = memo(function TaskConfigForm({ fields, fieldGroups, config, onChange, className, }) {
    const groupedFields = groupFieldsByGroup(fields, fieldGroups);
    if (fields.length === 0) {
        return (_jsx("div", { className: cn("px-3 py-4 text-xs text-[var(--stgm-muted-foreground,#737373)]", className), children: "No configurable fields for this task kind." }));
    }
    return (_jsx("div", { className: cn("flex flex-col gap-1", className), children: groupedFields.map((group) => (_jsx(FieldGroupSection, { group: group, config: config, onChange: onChange }, group.id))) }));
});
function FieldGroupSection({ group, config, onChange, }) {
    const [collapsed, setCollapsed] = useState(group.id === "__advanced");
    const toggle = useCallback(() => setCollapsed((c) => !c), []);
    return (_jsxs("div", { className: "border-b border-[var(--stgm-border,#e5e5e5)] last:border-b-0", children: [_jsxs("button", { type: "button", onClick: toggle, 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": !collapsed, children: [_jsx(ChevronIcon, { collapsed: collapsed }), group.displayName] }), !collapsed && (_jsxs("div", { className: "flex flex-col gap-3 px-3 pb-3", children: [group.description && (_jsx("p", { className: "text-[10px] text-[var(--stgm-muted-foreground,#737373)]", children: group.description })), group.fields.map((field) => (_jsx(FieldRenderer, { field: field, value: getFieldValue(config, field.name), onChange: (value) => onChange(field.name, value), depth: 0 }, field.name)))] }))] }));
}
// ---------------------------------------------------------------------------
// FieldRenderer
// ---------------------------------------------------------------------------
function FieldRenderer({ field, value, onChange, depth, }) {
    return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("label", { className: "flex items-center gap-1 text-[11px] font-medium text-[var(--stgm-foreground,#1a1a2e)]", children: [field.displayName, field.required && (_jsx("span", { className: "text-[var(--stgm-destructive,#ef4444)]", "aria-label": "required", children: "*" })), field.isExpression && (_jsx("span", { className: "rounded bg-[var(--stgm-accent,#e5e5e5)] px-1 text-[9px] font-normal text-[var(--stgm-muted-foreground,#737373)]", children: "expr" }))] }), field.description && (_jsx("p", { className: "text-[10px] leading-tight text-[var(--stgm-muted-foreground,#737373)]", children: field.description })), _jsx(FieldControl, { field: field, value: value, onChange: onChange, depth: depth })] }));
}
// ---------------------------------------------------------------------------
// FieldControl — type dispatch
// ---------------------------------------------------------------------------
function FieldControl({ field, value, onChange, depth, }) {
    switch (field.type) {
        case "string":
            return _jsx(StringField, { field: field, value: value, onChange: onChange });
        case "int32":
        case "float":
            return _jsx(NumberField, { field: field, value: value, onChange: onChange });
        case "bool":
            return _jsx(BoolField, { value: value, onChange: onChange });
        case "enum":
            return _jsx(EnumField, { field: field, value: value, onChange: onChange });
        case "struct":
        case "message":
            if (depth >= MAX_RECURSION_DEPTH) {
                return _jsx(JsonField, { value: value, onChange: onChange });
            }
            return _jsx(JsonField, { value: value, onChange: onChange });
        case "repeated":
            return _jsx(RepeatedField, { field: field, value: value, onChange: onChange });
        case "map":
            return _jsx(MapField, { value: value, onChange: onChange });
        default:
            return _jsx(JsonField, { value: value, onChange: onChange });
    }
}
// ---------------------------------------------------------------------------
// Concrete field controls
// ---------------------------------------------------------------------------
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)]";
function StringField({ field, value, onChange, }) {
    const strValue = typeof value === "string" ? value : "";
    const isMultiline = MULTILINE_FIELD_PATTERNS.test(field.name);
    const placeholder = field.isExpression ? "${...}" : field.defaultValue ?? "";
    const handleChange = useCallback((e) => {
        onChange(e.target.value || undefined);
    }, [onChange]);
    if (isMultiline) {
        return (_jsx("textarea", { value: strValue, onChange: handleChange, placeholder: placeholder, rows: 4, className: cn(inputClass, "resize-y font-mono", field.isExpression && "border-[var(--stgm-chart-purple,#8b5cf6)]/40") }));
    }
    return (_jsx("input", { type: "text", value: strValue, onChange: handleChange, placeholder: placeholder, className: cn(inputClass, field.isExpression && "border-[var(--stgm-chart-purple,#8b5cf6)]/40") }));
}
function NumberField({ field, value, onChange, }) {
    const numValue = typeof value === "number" ? value : "";
    const handleChange = useCallback((e) => {
        const v = e.target.value;
        if (v === "") {
            onChange(undefined);
            return;
        }
        const parsed = field.type === "float" ? parseFloat(v) : parseInt(v, 10);
        if (!isNaN(parsed))
            onChange(parsed);
    }, [onChange, field.type]);
    return (_jsx("input", { type: "number", value: numValue, onChange: handleChange, placeholder: field.defaultValue ?? "", step: field.type === "float" ? "any" : "1", className: inputClass }));
}
function BoolField({ value, onChange, }) {
    const checked = value === true;
    const handleChange = useCallback((e) => {
        onChange(e.target.checked);
    }, [onChange]);
    return (_jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: checked, onChange: handleChange, className: "h-4 w-4 rounded border-[var(--stgm-border,#d4d4d8)] text-[var(--stgm-primary,#6366f1)] focus:ring-[var(--stgm-ring,#3b82f6)]" }), _jsx("span", { className: "text-xs text-[var(--stgm-muted-foreground,#737373)]", children: checked ? "Enabled" : "Disabled" })] }));
}
function EnumField({ field, value, onChange, }) {
    const strValue = typeof value === "string" ? value : "";
    const handleChange = useCallback((e) => {
        onChange(e.target.value || undefined);
    }, [onChange]);
    return (_jsxs("select", { value: strValue, onChange: handleChange, className: inputClass, children: [_jsx("option", { value: "", children: "\u2014 Select \u2014" }), field.enumValues?.map((ev) => (_jsx("option", { value: ev, children: formatEnumLabel(ev) }, ev)))] }));
}
function JsonField({ value, onChange, }) {
    const strValue = value != null ? JSON.stringify(value, null, 2) : "";
    const [localValue, setLocalValue] = useState(strValue);
    const [parseError, setParseError] = useState(null);
    const handleChange = useCallback((e) => {
        const raw = e.target.value;
        setLocalValue(raw);
        if (!raw.trim()) {
            setParseError(null);
            onChange(undefined);
            return;
        }
        try {
            const parsed = JSON.parse(raw);
            setParseError(null);
            onChange(parsed);
        }
        catch {
            setParseError("Invalid JSON");
        }
    }, [onChange]);
    return (_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("textarea", { value: localValue, onChange: handleChange, rows: 4, className: cn(inputClass, "resize-y font-mono text-[11px]"), placeholder: "{}" }), parseError && (_jsx("span", { className: "text-[10px] text-[var(--stgm-destructive,#ef4444)]", children: parseError }))] }));
}
function RepeatedField({ field, value, onChange, }) {
    const items = Array.isArray(value) ? value : [];
    const addItem = useCallback(() => {
        onChange([...items, getDefaultForType(field.elementType)]);
    }, [items, onChange, field.elementType]);
    const removeItem = useCallback((idx) => {
        onChange(items.filter((_, i) => i !== idx));
    }, [items, onChange]);
    const updateItem = useCallback((idx, val) => {
        const next = [...items];
        next[idx] = val;
        onChange(next);
    }, [items, onChange]);
    return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [items.map((item, idx) => (_jsxs("div", { className: "flex items-start gap-1", children: [_jsx("input", { type: "text", value: typeof item === "string" ? item : JSON.stringify(item ?? ""), onChange: (e) => updateItem(idx, e.target.value || undefined), className: cn(inputClass, "flex-1") }), _jsx("button", { type: "button", onClick: () => removeItem(idx), className: "mt-1 text-[10px] text-[var(--stgm-destructive,#ef4444)] hover:underline", "aria-label": `Remove item ${idx + 1}`, children: "\u2715" })] }, idx))), _jsx("button", { type: "button", onClick: addItem, className: "self-start text-[11px] font-medium text-[var(--stgm-primary,#6366f1)] hover:underline", children: "+ Add item" })] }));
}
function MapField({ value, onChange, }) {
    const obj = (value != null && typeof value === "object" && !Array.isArray(value))
        ? value
        : {};
    const entries = Object.entries(obj);
    const addEntry = useCallback(() => {
        onChange({ ...obj, "": "" });
    }, [obj, onChange]);
    const removeEntry = useCallback((key) => {
        const { [key]: _, ...rest } = obj;
        onChange(Object.keys(rest).length > 0 ? rest : undefined);
    }, [obj, onChange]);
    const updateEntry = useCallback((oldKey, newKey, val) => {
        const result = {};
        for (const [k, v] of Object.entries(obj)) {
            if (k === oldKey) {
                result[newKey] = val;
            }
            else {
                result[k] = v;
            }
        }
        onChange(result);
    }, [obj, onChange]);
    return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [entries.map(([key, val], idx) => (_jsxs("div", { className: "flex items-start gap-1", children: [_jsx("input", { type: "text", value: key, onChange: (e) => updateEntry(key, e.target.value, val), placeholder: "key", className: cn(inputClass, "w-1/3") }), _jsx("input", { type: "text", value: typeof val === "string" ? val : JSON.stringify(val ?? ""), onChange: (e) => updateEntry(key, key, e.target.value || undefined), placeholder: "value", className: cn(inputClass, "flex-1") }), _jsx("button", { type: "button", onClick: () => removeEntry(key), className: "mt-1 text-[10px] text-[var(--stgm-destructive,#ef4444)] hover:underline", "aria-label": `Remove entry ${key}`, children: "\u2715" })] }, idx))), _jsx("button", { type: "button", onClick: addEntry, className: "self-start text-[11px] font-medium text-[var(--stgm-primary,#6366f1)] hover:underline", children: "+ Add entry" })] }));
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function ChevronIcon({ collapsed }) {
    return (_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", !collapsed && "rotate-90"), children: _jsx("path", { d: "M6 4l4 4-4 4" }) }));
}
function groupFieldsByGroup(fields, fieldGroups) {
    const groupMap = new Map();
    const ungrouped = [];
    for (const field of fields) {
        if (field.groupId) {
            const existing = groupMap.get(field.groupId);
            if (existing) {
                existing.push(field);
            }
            else {
                groupMap.set(field.groupId, [field]);
            }
        }
        else {
            ungrouped.push(field);
        }
    }
    const result = [];
    if (ungrouped.length > 0) {
        result.push({ id: "__general", displayName: "General", fields: ungrouped });
    }
    for (const group of fieldGroups) {
        const groupFields = groupMap.get(group.id);
        if (groupFields && groupFields.length > 0) {
            result.push({
                id: group.id,
                displayName: group.displayName,
                description: group.description,
                fields: groupFields,
            });
        }
    }
    return result;
}
function getFieldValue(config, fieldName) {
    return config[fieldName];
}
function formatEnumLabel(value) {
    return value.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}
function getDefaultForType(elementType) {
    switch (elementType) {
        case "int32":
        case "float":
            return 0;
        case "bool":
            return false;
        default:
            return "";
    }
}
//# sourceMappingURL=TaskConfigForm.js.map