import React, { useEffect, useMemo, useRef, useState, } from "react";
import API from "../../Utils/API/API";
import { WORKFLOW_URL } from "../../Config";
import URL from "../../../Types/API/URL";
import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
import ComponentLoader from "../ComponentLoader/ComponentLoader";
import CodeEditor from "../CodeEditor/CodeEditor";
import CodeType from "../../../Types/Code/CodeType";
import Icon from "../Icon/Icon";
import IconProp from "../../../Types/Icon/IconProp";
/*
 * normalizeInitialValue turns the raw stored value (which may be a JSON
 * string, an already-parsed object, null, or empty) into a `{ text, parsed }`
 * pair. `parsed` is null when the text doesn't parse as a JSON object.
 */
const normalizeInitialValue = (value) => {
    if (value === null || value === undefined || value === "") {
        return { text: "", parsed: null };
    }
    if (typeof value === "string") {
        try {
            const parsed = JSON.parse(value);
            if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
                return { text: value, parsed: parsed };
            }
            return { text: value, parsed: null };
        }
        catch (_a) {
            return { text: value, parsed: null };
        }
    }
    // Already an object.
    if (typeof value === "object" && !Array.isArray(value)) {
        return {
            text: JSON.stringify(value, null, 2),
            parsed: value,
        };
    }
    return { text: String(value), parsed: null };
};
/*
 * Decide whether an existing select value can be represented by the picker.
 * Returns a list of human-readable reasons when not — we surface those in a
 * banner so the user understands why we're keeping their JSON as-is.
 */
const classifyCompatibility = (text, parsed, columns) => {
    // Empty value: picker can represent it (as nothing selected).
    if (text.trim() === "" || parsed === null) {
        if (text.trim() === "") {
            return { compatible: true, reasons: [], parsed: {} };
        }
        return {
            compatible: false,
            reasons: ["The current value isn't valid JSON."],
            parsed: null,
        };
    }
    const reasons = [];
    const columnsById = {};
    for (const c of columns) {
        columnsById[c.id] = c;
    }
    for (const key of Object.keys(parsed)) {
        const column = columnsById[key];
        if (!column) {
            reasons.push(`"${key}" isn't a readable field on this model.`);
            continue;
        }
        const value = parsed[key];
        if (column.isRelation) {
            if (value === true) {
                /*
                 * The picker requires at least one sub-field for a relation. Hidden in
                 * the picker UI on purpose.
                 */
                reasons.push(`"${key}" selects the whole relation. The picker requires you to pick specific sub-fields.`);
                continue;
            }
            if (value === null || typeof value !== "object" || Array.isArray(value)) {
                reasons.push(`"${key}" has an unexpected value.`);
                continue;
            }
            const subColumnsById = {};
            for (const sub of column.relatedColumns || []) {
                subColumnsById[sub.id] = sub;
            }
            for (const subKey of Object.keys(value)) {
                const subValue = value[subKey];
                const subColumn = subColumnsById[subKey];
                if (!subColumn) {
                    reasons.push(`"${key}.${subKey}" isn't a readable field on the related model.`);
                    continue;
                }
                if (subColumn.isRelation) {
                    reasons.push(`"${key}.${subKey}" is nested more than one level deep.`);
                    continue;
                }
                if (typeof subValue !== "boolean") {
                    if (typeof subValue === "object" && subValue !== null) {
                        reasons.push(`"${key}.${subKey}" is nested more than one level deep.`);
                    }
                    else {
                        reasons.push(`"${key}.${subKey}" has an unexpected value.`);
                    }
                }
            }
            continue;
        }
        // Scalar column.
        if (typeof value !== "boolean") {
            reasons.push(`"${key}" has an unexpected value.`);
        }
    }
    return {
        compatible: reasons.length === 0,
        reasons,
        parsed,
    };
};
/*
 * Convert the picker's checkbox state into the JSON object that goes back
 * into the workflow argument. Empty selections collapse to an empty string
 * (rather than "{}") so existing "required" validation continues to work.
 */
const buildSelectJson = (scalarChecks, relationChecks) => {
    const out = {};
    for (const id of scalarChecks) {
        out[id] = true;
    }
    for (const relation of Object.keys(relationChecks)) {
        const set = relationChecks[relation];
        if (!set || set.size === 0) {
            continue;
        }
        const subObj = {};
        for (const subId of set) {
            subObj[subId] = true;
        }
        out[relation] = subObj;
    }
    if (Object.keys(out).length === 0) {
        return "";
    }
    return JSON.stringify(out);
};
const PickerCheckbox = (props) => {
    const ref = useRef(null);
    useEffect(() => {
        if (ref.current) {
            ref.current.indeterminate = Boolean(props.indeterminate);
        }
    }, [props.indeterminate]);
    const sizeClass = props.size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4";
    return (React.createElement("input", { ref: ref, type: "checkbox", checked: props.checked, onChange: props.onChange, onClick: (e) => {
            // Prevent toggling parent label/row when the click originates here.
            e.stopPropagation();
        }, "aria-label": props.ariaLabel, className: `${sizeClass} rounded border-gray-300 text-indigo-600 focus:ring-1 focus:ring-indigo-500 focus:ring-offset-0 cursor-pointer` }));
};
const ModelFieldPicker = (props) => {
    const [columns, setColumns] = useState(null);
    const [isLoading, setIsLoading] = useState(true);
    const [loadError, setLoadError] = useState(null);
    const initial = useMemo(() => {
        return normalizeInitialValue(props.initialValue);
    }, []);
    const [jsonText, setJsonText] = useState(initial.text);
    const [viewMode, setViewMode] = useState("picker");
    const [incompatibilityReasons, setIncompatibilityReasons] = useState([]);
    const [isLockedToJson, setIsLockedToJson] = useState(false);
    // Checkbox state for picker mode.
    const [scalarChecks, setScalarChecks] = useState(new Set());
    const [relationChecks, setRelationChecks] = useState({});
    const [expandedRelations, setExpandedRelations] = useState(new Set());
    const [searchQuery, setSearchQuery] = useState("");
    // Avoid re-emitting onChange for the initial value (preserves byte-for-byte).
    const hasInitializedFromColumns = useRef(false);
    useEffect(() => {
        let cancelled = false;
        const loadSchema = async () => {
            setIsLoading(true);
            setLoadError(null);
            try {
                const url = URL.fromString(WORKFLOW_URL.toString()).addRoute(`/model-schema/${encodeURIComponent(props.tableName)}`);
                const result = await API.get({ url });
                if (cancelled) {
                    return;
                }
                if (result instanceof HTTPErrorResponse) {
                    throw result;
                }
                const data = result.data;
                setColumns(data.columns || []);
            }
            catch (err) {
                if (cancelled) {
                    return;
                }
                setLoadError(API.getFriendlyMessage(err));
                setColumns([]);
            }
            finally {
                if (!cancelled) {
                    setIsLoading(false);
                }
            }
        };
        void loadSchema();
        return () => {
            cancelled = true;
        };
    }, [props.tableName]);
    /*
     * Apply a classification result to picker state: either seed the checkboxes
     * (compatible) or lock the editor to JSON mode with reasons (incompatible).
     */
    const applyClassification = (result, cols) => {
        if (!result.compatible) {
            setIncompatibilityReasons(result.reasons);
            setIsLockedToJson(true);
            setViewMode("json");
            return;
        }
        const parsed = result.parsed || {};
        const nextScalars = new Set();
        const nextRelations = {};
        const nextExpanded = new Set();
        const columnsById = {};
        for (const c of cols) {
            columnsById[c.id] = c;
        }
        for (const key of Object.keys(parsed)) {
            const column = columnsById[key];
            if (!column) {
                continue;
            }
            if (column.isRelation) {
                const sub = parsed[key] || {};
                const set = new Set();
                for (const subKey of Object.keys(sub)) {
                    if (sub[subKey] === true) {
                        set.add(subKey);
                    }
                }
                if (set.size > 0) {
                    nextRelations[key] = set;
                    nextExpanded.add(key);
                }
            }
            else if (parsed[key] === true) {
                nextScalars.add(key);
            }
        }
        setScalarChecks(nextScalars);
        setRelationChecks(nextRelations);
        setExpandedRelations(nextExpanded);
        setIncompatibilityReasons([]);
        setIsLockedToJson(false);
        setViewMode("picker");
    };
    // Once we have columns, classify the initial value and seed picker state.
    useEffect(() => {
        if (columns === null) {
            return;
        }
        if (hasInitializedFromColumns.current) {
            return;
        }
        hasInitializedFromColumns.current = true;
        const result = classifyCompatibility(initial.text, initial.parsed, columns);
        applyClassification(result, columns);
    }, [columns, initial.text, initial.parsed]);
    // When the picker emits, push JSON upward.
    const emitFromPicker = (scalars, relations) => {
        const next = buildSelectJson(scalars, relations);
        setJsonText(next);
        props.onChange(next);
    };
    const toggleScalar = (id) => {
        const next = new Set(scalarChecks);
        if (next.has(id)) {
            next.delete(id);
        }
        else {
            next.add(id);
        }
        setScalarChecks(next);
        emitFromPicker(next, relationChecks);
    };
    const toggleRelationField = (relation, sub) => {
        const existing = new Set(relationChecks[relation] || []);
        if (existing.has(sub)) {
            existing.delete(sub);
        }
        else {
            existing.add(sub);
        }
        const next = Object.assign({}, relationChecks);
        if (existing.size === 0) {
            delete next[relation];
        }
        else {
            next[relation] = existing;
        }
        setRelationChecks(next);
        emitFromPicker(scalarChecks, next);
    };
    const toggleExpand = (relation) => {
        const next = new Set(expandedRelations);
        if (next.has(relation)) {
            next.delete(relation);
        }
        else {
            next.add(relation);
        }
        setExpandedRelations(next);
    };
    /*
     * Select-all / clear helpers operate on whatever's currently visible so
     * the actions feel scoped to what the user can see.
     */
    const setScalarSelection = (ids) => {
        const next = new Set(ids);
        setScalarChecks(next);
        emitFromPicker(next, relationChecks);
    };
    const setRelationSelection = (relation, ids) => {
        const next = Object.assign({}, relationChecks);
        if (ids.length === 0) {
            delete next[relation];
        }
        else {
            next[relation] = new Set(ids);
        }
        setRelationChecks(next);
        emitFromPicker(scalarChecks, next);
    };
    const expandRelation = (relation) => {
        if (expandedRelations.has(relation)) {
            return;
        }
        const next = new Set(expandedRelations);
        next.add(relation);
        setExpandedRelations(next);
    };
    const onSearchChange = (value) => {
        setSearchQuery(value);
    };
    /*
     * Friendly type-pill label. Returns null for plain text-like columns so the
     * common case stays uncluttered.
     */
    const getTypeLabel = (type) => {
        const map = {
            Date: "Date",
            Boolean: "Yes / No",
            Number: "Number",
            "Big Number": "Number",
            "Small Number": "Number",
            "Positive Number": "Number",
            "Small Positive Number": "Number",
            "Big Positive Number": "Number",
            "Object ID": "ID",
            Slug: "Slug",
            URL: "URL",
            Email: "Email",
            Phone: "Phone",
            IP: "IP",
            Port: "Port",
            Color: "Color",
            JSON: "JSON",
            Markdown: "Markdown",
            HTML: "HTML",
            "Entity Array": "List",
        };
        return map[type] || null;
    };
    const matchesQuery = (column, query) => {
        if (!query) {
            return true;
        }
        return (column.title.toLowerCase().includes(query) ||
            column.id.toLowerCase().includes(query) ||
            (column.description || "").toLowerCase().includes(query));
    };
    const onJsonChange = (next) => {
        setJsonText(next);
        props.onChange(next);
    };
    const resetToPicker = () => {
        setIncompatibilityReasons([]);
        setIsLockedToJson(false);
        setScalarChecks(new Set());
        setRelationChecks({});
        setExpandedRelations(new Set());
        setJsonText("");
        props.onChange("");
        setViewMode("picker");
    };
    if (isLoading) {
        return (React.createElement("div", { className: "py-10" },
            React.createElement(ComponentLoader, null)));
    }
    const scalarColumns = (columns || []).filter((c) => {
        return !c.isRelation;
    });
    const relationColumns = (columns || []).filter((c) => {
        return c.isRelation;
    });
    const totalSelected = scalarChecks.size +
        Object.values(relationChecks).reduce((acc, s) => {
            return acc + s.size;
        }, 0);
    const totalAvailable = scalarColumns.length +
        relationColumns.reduce((acc, r) => {
            var _a;
            return acc + (((_a = r.relatedColumns) === null || _a === void 0 ? void 0 : _a.length) || 0);
        }, 0);
    const onUsePickerClicked = () => {
        if (!columns) {
            return;
        }
        // Re-classify the current JSON text — the user may have edited it.
        const norm = normalizeInitialValue(jsonText);
        const result = classifyCompatibility(norm.text, norm.parsed, columns);
        applyClassification(result, columns);
    };
    /*
     * Apply search filter. For relations, the relation passes if its own title
     * matches OR any sub-field matches; in the latter case we auto-expand it so
     * the matching child is visible.
     */
    const query = searchQuery.trim().toLowerCase();
    const visibleScalars = scalarColumns.filter((c) => {
        return matchesQuery(c, query);
    });
    const visibleRelations = relationColumns
        .map((column) => {
        const subMatches = (column.relatedColumns || []).filter((sub) => {
            return matchesQuery(sub, query);
        });
        const matchesSelf = matchesQuery(column, query);
        if (query && !matchesSelf && subMatches.length === 0) {
            return null;
        }
        return {
            column,
            visibleSubs: query && !matchesSelf ? subMatches : column.relatedColumns || [],
            matchedByChild: query.length > 0 && !matchesSelf && subMatches.length > 0,
        };
    })
        .filter((x) => {
        return x !== null;
    });
    const hasNoVisibleResults = visibleScalars.length === 0 && visibleRelations.length === 0;
    const selectAllScalars = () => {
        const ids = visibleScalars.map((c) => {
            return c.id;
        });
        // Merge with existing so out-of-view (filtered) selections aren't lost.
        const merged = new Set(scalarChecks);
        for (const id of ids) {
            merged.add(id);
        }
        setScalarSelection(Array.from(merged));
    };
    const clearAllScalars = () => {
        // Only clear what's visible — preserves selections hidden by search.
        const next = new Set(scalarChecks);
        for (const c of visibleScalars) {
            next.delete(c.id);
        }
        setScalarSelection(Array.from(next));
    };
    /*
     * Renders one selectable field row. Used for both top-level scalars and
     * relation sub-fields (which pass a denser variant via `dense`).
     */
    const renderFieldRow = (args) => {
        const { column, checked, onToggle, dense } = args;
        const typeLabel = getTypeLabel(column.type);
        return (React.createElement("label", { className: `group relative flex items-center gap-3 ${dense ? "py-1.5" : "py-2"} px-3 cursor-pointer select-none transition-colors ${checked ? "bg-indigo-50/40" : "hover:bg-gray-50/80"}` },
            checked && (React.createElement("span", { className: "absolute left-0 top-1 bottom-1 w-0.5 rounded-r bg-indigo-500", "aria-hidden": "true" })),
            React.createElement("input", { type: "checkbox", checked: checked, onChange: onToggle, className: "h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-1 focus:ring-indigo-500 focus:ring-offset-0 cursor-pointer" }),
            React.createElement("span", { className: "flex-1 min-w-0" },
                React.createElement("span", { className: "flex items-baseline gap-2" },
                    React.createElement("span", { className: `truncate text-sm ${checked
                            ? "font-medium text-gray-900"
                            : "font-medium text-gray-800"}` }, column.title),
                    typeLabel && (React.createElement("span", { className: "ml-auto flex-shrink-0 text-[11px] uppercase tracking-wider text-gray-400 group-hover:text-gray-500" }, typeLabel))),
                column.description && (React.createElement("span", { className: "block text-xs text-gray-500 truncate mt-0.5", title: column.description }, column.description)))));
    };
    /*
     * Top-level toolbar above everything: search on the left (when in picker
     * mode), then count, then the view-mode toggle. Kept as a single tight row
     * so it doesn't visually compete with the field list below.
     */
    const renderToolbar = () => {
        const showSearch = viewMode === "picker" && !isLockedToJson && totalAvailable > 0;
        let toggleLabel;
        let toggleIcon;
        let toggleHandler;
        if (isLockedToJson) {
            toggleLabel = "Reset to picker";
            toggleIcon = IconProp.Refresh;
            toggleHandler = resetToPicker;
        }
        else if (viewMode === "picker") {
            toggleLabel = "JSON";
            toggleIcon = IconProp.Code;
            toggleHandler = () => {
                setViewMode("json");
            };
        }
        else {
            toggleLabel = "Picker";
            toggleIcon = IconProp.ListBullet;
            toggleHandler = onUsePickerClicked;
        }
        return (React.createElement("div", { className: "flex items-center gap-2" },
            showSearch && (React.createElement("div", { className: "relative flex-1" },
                React.createElement("span", { className: "pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3" },
                    React.createElement(Icon, { icon: IconProp.MagnifyingGlass, className: "h-4 w-4 text-gray-400" })),
                React.createElement("input", { type: "text", value: searchQuery, onChange: (e) => {
                        return onSearchChange(e.target.value);
                    }, placeholder: `Search ${totalAvailable} fields`, className: "block w-full rounded-md border border-gray-200 bg-white pl-9 pr-8 py-1.5 text-sm placeholder-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" }),
                searchQuery && (React.createElement("button", { type: "button", onClick: () => {
                        return setSearchQuery("");
                    }, className: "absolute inset-y-0 right-0 flex items-center pr-2.5 text-gray-400 hover:text-gray-600", "aria-label": "Clear search" },
                    React.createElement(Icon, { icon: IconProp.Close, className: "h-3.5 w-3.5" }))))),
            !showSearch && React.createElement("div", { className: "flex-1" }),
            !isLockedToJson && totalAvailable > 0 && viewMode === "picker" && (React.createElement("span", { className: "text-xs text-gray-500 whitespace-nowrap font-mono" },
                React.createElement("span", { className: `${totalSelected > 0
                        ? "font-semibold text-indigo-600"
                        : "text-gray-700"}` }, totalSelected),
                React.createElement("span", { className: "text-gray-300 mx-1" }, "/"),
                React.createElement("span", null, totalAvailable))),
            React.createElement("button", { type: "button", onClick: toggleHandler, className: "inline-flex items-center gap-1.5 rounded-md border border-gray-200 bg-white px-2.5 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:ring-1 focus:ring-indigo-500" },
                React.createElement(Icon, { icon: toggleIcon, className: "h-3.5 w-3.5 text-gray-500" }),
                toggleLabel)));
    };
    const renderSectionHeader = (args) => {
        return (React.createElement("div", { className: "flex items-center justify-between px-3 pt-3 pb-1.5" },
            React.createElement("span", { className: "text-[10px] font-semibold uppercase tracking-[0.08em] text-gray-400" }, args.label),
            args.actions ? (React.createElement("div", { className: "flex items-center gap-1 text-[11px]" }, args.actions)) : null));
    };
    const renderSectionActions = (args) => {
        return (React.createElement(React.Fragment, null,
            React.createElement("button", { type: "button", onClick: args.onSelectAll, className: "font-medium text-indigo-600 hover:text-indigo-700" }, "Select all"),
            React.createElement("span", { className: "text-gray-300" }, "\u00B7"),
            React.createElement("button", { type: "button", onClick: args.onClear, className: "font-medium text-gray-500 hover:text-gray-700" }, "Clear")));
    };
    return (React.createElement("div", { className: "space-y-2" },
        renderToolbar(),
        loadError && (React.createElement("div", { className: "flex items-start gap-2.5 rounded-md border border-red-200 bg-red-50/60 px-3 py-2 text-xs text-red-800" },
            React.createElement(Icon, { icon: IconProp.AltGlobe, className: "h-4 w-4 text-red-600 mt-0.5 flex-shrink-0" }),
            React.createElement("div", null,
                React.createElement("p", { className: "font-semibold" }, "Could not load fields"),
                React.createElement("p", { className: "text-red-700" }, loadError)))),
        isLockedToJson && (React.createElement("div", { className: "rounded-md border border-amber-200 bg-amber-50/60 px-3 py-2.5" },
            React.createElement("div", { className: "flex items-start gap-2.5" },
                React.createElement(Icon, { icon: IconProp.Info, className: "h-4 w-4 text-amber-600 mt-0.5 flex-shrink-0" }),
                React.createElement("div", { className: "text-xs text-amber-900 space-y-1" },
                    React.createElement("p", { className: "font-semibold" }, "Keeping your selection as JSON"),
                    React.createElement("ul", { className: "text-amber-800 space-y-0.5 list-disc pl-4" }, incompatibilityReasons.map((reason, i) => {
                        return React.createElement("li", { key: i }, reason);
                    })),
                    React.createElement("p", { className: "pt-0.5 text-amber-700/80" },
                        "Your workflow keeps running unchanged. Edit the JSON below, or click ",
                        React.createElement("strong", null, "Reset to picker"),
                        " to start fresh."))))),
        (viewMode === "json" || loadError) && (React.createElement("div", { className: "rounded-md border border-gray-200 overflow-hidden" },
            React.createElement(CodeEditor, { type: CodeType.JSON, value: jsonText, onChange: onJsonChange, placeholder: props.placeholder || 'Example: {"columnName": true, ...}', error: props.error, tabIndex: props.tabIndex }))),
        viewMode === "picker" && !loadError && (React.createElement("div", { className: "rounded-md border border-gray-200 bg-white" },
            totalAvailable === 0 && (React.createElement("div", { className: "px-6 py-12 text-center" },
                React.createElement(Icon, { icon: IconProp.Database, className: "h-6 w-6 mx-auto text-gray-300 mb-2" }),
                React.createElement("p", { className: "text-sm text-gray-500" }, "No readable fields are available for this model."))),
            totalAvailable > 0 && hasNoVisibleResults && (React.createElement("div", { className: "px-6 py-10 text-center" },
                React.createElement(Icon, { icon: IconProp.MagnifyingGlass, className: "h-5 w-5 mx-auto text-gray-300 mb-2" }),
                React.createElement("p", { className: "text-sm text-gray-600" },
                    "No fields match",
                    " ",
                    React.createElement("span", { className: "font-medium text-gray-900" },
                        "\u201C",
                        searchQuery,
                        "\u201D")),
                React.createElement("button", { type: "button", onClick: () => {
                        return setSearchQuery("");
                    }, className: "mt-2 text-xs font-medium text-indigo-600 hover:text-indigo-700" }, "Clear search"))),
            visibleScalars.length > 0 && (React.createElement(React.Fragment, null,
                renderSectionHeader({
                    label: "Fields",
                    actions: renderSectionActions({
                        onSelectAll: selectAllScalars,
                        onClear: clearAllScalars,
                    }),
                }),
                React.createElement("div", { className: "divide-y divide-gray-100" }, visibleScalars.map((column) => {
                    return (React.createElement(React.Fragment, { key: column.id }, renderFieldRow({
                        column,
                        checked: scalarChecks.has(column.id),
                        onToggle: () => {
                            toggleScalar(column.id);
                        },
                    })));
                })))),
            visibleScalars.length > 0 && visibleRelations.length > 0 && (React.createElement("div", { className: "border-t border-gray-100 mt-2" })),
            visibleRelations.length > 0 && (React.createElement(React.Fragment, null,
                renderSectionHeader({
                    label: "Related records",
                    actions: (React.createElement("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-300" }, "1 level")),
                }),
                React.createElement("div", { className: "divide-y divide-gray-100" }, visibleRelations.map((entry) => {
                    const column = entry.column;
                    const visibleSubs = entry.visibleSubs;
                    const totalSubs = (column.relatedColumns || [])
                        .length;
                    const selectedSubs = relationChecks[column.id] || new Set();
                    const isExpanded = expandedRelations.has(column.id) || entry.matchedByChild;
                    const allChecked = totalSubs > 0 && selectedSubs.size === totalSubs;
                    const someChecked = selectedSubs.size > 0 && !allChecked;
                    const toggleAllSubs = () => {
                        if (allChecked) {
                            setRelationSelection(column.id, []);
                        }
                        else {
                            const ids = (column.relatedColumns || []).map((s) => {
                                return s.id;
                            });
                            setRelationSelection(column.id, ids);
                            expandRelation(column.id);
                        }
                    };
                    const selectAllSubs = () => {
                        const ids = visibleSubs.map((s) => {
                            return s.id;
                        });
                        const merged = new Set(selectedSubs);
                        for (const id of ids) {
                            merged.add(id);
                        }
                        setRelationSelection(column.id, Array.from(merged));
                    };
                    const clearSubs = () => {
                        const next = new Set(selectedSubs);
                        for (const s of visibleSubs) {
                            next.delete(s.id);
                        }
                        setRelationSelection(column.id, Array.from(next));
                    };
                    return (React.createElement("div", { key: column.id, className: `${isExpanded ? "bg-gray-50/40" : ""}` },
                        React.createElement("div", { className: `relative flex items-center gap-3 px-3 py-2 transition-colors ${isExpanded ? "" : "hover:bg-gray-50/80"}` },
                            (allChecked || someChecked) && (React.createElement("span", { className: "absolute left-0 top-1 bottom-1 w-0.5 rounded-r bg-indigo-500", "aria-hidden": "true" })),
                            React.createElement(PickerCheckbox, { checked: allChecked, indeterminate: someChecked, onChange: toggleAllSubs, ariaLabel: `Select all from ${column.title}` }),
                            React.createElement("button", { type: "button", onClick: () => {
                                    return toggleExpand(column.id);
                                }, className: "flex-1 flex items-center justify-between gap-2 text-left min-w-0" },
                                React.createElement("span", { className: "min-w-0 flex items-baseline gap-2" },
                                    React.createElement("span", { className: `truncate text-sm font-medium ${allChecked || someChecked
                                            ? "text-gray-900"
                                            : "text-gray-800"}` }, column.title),
                                    column.relatedTableName && (React.createElement("span", { className: "text-[11px] text-gray-400" }, column.relatedTableName))),
                                React.createElement("span", { className: "flex items-center gap-2 flex-shrink-0" },
                                    React.createElement("span", { className: "text-[11px] text-gray-500 font-mono whitespace-nowrap" },
                                        React.createElement("span", { className: selectedSubs.size > 0
                                                ? "font-semibold text-indigo-600"
                                                : "text-gray-400" }, selectedSubs.size),
                                        React.createElement("span", { className: "text-gray-300 mx-1" }, "/"),
                                        React.createElement("span", null, totalSubs)),
                                    React.createElement(Icon, { icon: isExpanded
                                            ? IconProp.ChevronDown
                                            : IconProp.ChevronRight, className: "h-3.5 w-3.5 text-gray-400" })))),
                        isExpanded && (React.createElement("div", { className: "pl-7 pr-0 pb-1 border-l-2 border-indigo-100 ml-5 mb-1" },
                            React.createElement("div", { className: "flex items-center justify-between px-3 py-1.5" },
                                React.createElement("span", { className: "text-[10px] uppercase tracking-wider text-gray-400 font-medium" }, "Sub-fields"),
                                React.createElement("div", { className: "flex items-center gap-1 text-[11px]" }, renderSectionActions({
                                    onSelectAll: selectAllSubs,
                                    onClear: clearSubs,
                                }))),
                            React.createElement("div", { className: "divide-y divide-gray-100" }, visibleSubs.map((sub) => {
                                return (React.createElement(React.Fragment, { key: sub.id }, renderFieldRow({
                                    column: sub,
                                    checked: selectedSubs.has(sub.id),
                                    onToggle: () => {
                                        toggleRelationField(column.id, sub.id);
                                    },
                                    dense: true,
                                })));
                            }))))));
                })))),
            (visibleScalars.length > 0 || visibleRelations.length > 0) && (React.createElement("div", { className: "py-1" })))),
        props.error && (React.createElement("p", { className: "text-xs text-red-600 mt-0.5", "data-testid": "error-message" }, props.error))));
};
export default ModelFieldPicker;
//# sourceMappingURL=ModelFieldPicker.js.map