import React, { useMemo } from "react";
import CopyableButton from "../CopyableButton/CopyableButton";
import Icon from "../Icon/Icon";
import IconProp from "../../../Types/Icon/IconProp";
import JSONFunctions from "../../../Types/JSONFunctions";
function normalizeValue(value) {
    if (value === null || value === undefined) {
        return "-";
    }
    if (typeof value === "object") {
        try {
            return JSON.stringify(value);
        }
        catch (_a) {
            return "[Object]";
        }
    }
    if (typeof value === "boolean") {
        return value ? "true" : "false";
    }
    // Fallback for numbers / strings / bigint / symbol etc.
    return String(value);
}
const JSONTable = (props) => {
    const { json } = props;
    const flatItems = useMemo(() => {
        if (!json) {
            return [];
        }
        const working = JSONFunctions.flattenObject(JSONFunctions.nestJson(json));
        const groupMap = {};
        const keys = Object.keys(working);
        // Track keys that should be removed after grouping
        const keysToRemove = new Set();
        // Helper to detect if a key has nested descendants
        const hasNestedDescendant = (k) => {
            const descendantPrefix = k + "."; // e.g. arr.0.
            return keys.some((other) => {
                return other.startsWith(descendantPrefix);
            });
        };
        for (const key of keys) {
            const match = key.match(/^(.*)\.(\d+)$/);
            if (!match || match.length < 3) {
                continue;
            }
            const prefix = match[1];
            const indexStr = match[2];
            const index = parseInt(indexStr, 10);
            // Skip if this index key has further nesting (e.g., arr.0.field)
            if (hasNestedDescendant(key)) {
                continue;
            }
            if (!groupMap[prefix]) {
                groupMap[prefix] = [];
            }
            // At this point groupMap[prefix] is initialized. Use a local ref so TS can narrow.
            const entries = groupMap[prefix];
            entries.push({ index, value: working[key] });
            keysToRemove.add(key);
        }
        // Apply grouping where it makes sense (only if at least 2 items or at least 1 and prefix not already defined)
        for (const prefix in groupMap) {
            const arr = groupMap[prefix] || [];
            if (arr.length === 0) {
                continue;
            }
            // Sort by numeric index
            arr.sort((a, b) => {
                return a.index - b.index;
            });
            // Always override / set grouped array representation.
            working[prefix] = arr.map((i) => {
                return i.value;
            });
        }
        // Remove grouped index keys
        for (const k of keysToRemove) {
            delete working[k];
        }
        return Object.keys(working)
            .sort()
            .map((key) => {
            return { key, value: normalizeValue(working[key]) };
        });
    }, [json]);
    if (!flatItems.length) {
        return (React.createElement("div", { className: "border border-dashed border-gray-300 rounded-md p-4 text-sm text-gray-500 bg-gray-50" }, "No attributes."));
    }
    return (React.createElement("div", { className: props.className },
        props.title && (React.createElement("div", { className: "text-sm font-semibold text-gray-700 mb-2" }, props.title)),
        React.createElement("div", { className: "overflow-hidden border border-gray-200 rounded-md" },
            React.createElement("table", { className: "min-w-full table-fixed" },
                React.createElement("thead", null,
                    React.createElement("tr", { className: "bg-gray-50 text-xs uppercase tracking-wider text-left text-gray-500" },
                        React.createElement("th", { className: "px-3 py-2 w-1/3" }, "Key"),
                        React.createElement("th", { className: "px-3 py-2" }, "Value"))),
                React.createElement("tbody", { className: "divide-y divide-gray-100" }, flatItems.map((item) => {
                    const canFilter = Boolean(props.onFilterByAttribute && item.value && item.value !== "-");
                    return (React.createElement("tr", { key: item.key, className: "group hover:bg-gray-50 text-sm" },
                        React.createElement("td", { className: "font-mono px-3 py-2 align-top text-gray-700 break-all whitespace-pre-wrap" }, item.key),
                        React.createElement("td", { className: "px-3 py-2 align-top break-all whitespace-pre-wrap font-mono text-gray-800" },
                            React.createElement("div", { className: "flex items-start" },
                                React.createElement("div", { className: "flex-1 pr-2" }, item.value.length > 500 ? (React.createElement("details", null,
                                    React.createElement("summary", { className: "cursor-pointer select-none text-gray-600" },
                                        "Show value (",
                                        item.value.length,
                                        " chars)"),
                                    React.createElement("pre", { className: "mt-1 text-xs overflow-auto max-h-64" }, item.value))) : (React.createElement("span", null, item.value))),
                                React.createElement("div", { className: "flex items-center gap-1 opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition-opacity duration-150" },
                                    canFilter && (React.createElement("button", { type: "button", className: "rounded p-1 text-gray-400 hover:bg-gray-100 hover:text-indigo-600", title: `Filter by ${item.key}: ${item.value}`, onClick: () => {
                                            props.onFilterByAttribute(item.key, item.value);
                                        } },
                                        React.createElement(Icon, { icon: IconProp.Filter, className: "h-3.5 w-3.5" }))),
                                    React.createElement(CopyableButton, { textToBeCopied: item.value }))))));
                }))))));
};
export default JSONTable;
//# sourceMappingURL=JSONTable.js.map