// Show a large modal full of components.
import ErrorMessage from "../ErrorMessage/ErrorMessage";
import Icon from "../Icon/Icon";
import SideOver from "../SideOver/SideOver";
import IconProp from "../../../Types/Icon/IconProp";
import React, { useEffect, useRef, useState, } from "react";
const escapeRegExp = (value) => {
    return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
};
const getSearchScore = (componentMetadata, searchTerm) => {
    const title = componentMetadata.title.toLowerCase();
    const description = componentMetadata.description.toLowerCase();
    const category = componentMetadata.category.toLowerCase();
    let score = 0;
    if (title.startsWith(searchTerm)) {
        score += 140;
    }
    else if (title.includes(searchTerm)) {
        score += 100;
    }
    if (category.startsWith(searchTerm)) {
        score += 75;
    }
    else if (category.includes(searchTerm)) {
        score += 55;
    }
    if (description.includes(searchTerm)) {
        score += 35;
    }
    if (title.split(" ").some((word) => {
        return word.trim().startsWith(searchTerm);
    })) {
        score += 15;
    }
    return score;
};
const ComponentsModal = (props) => {
    const [search, setSearch] = useState("");
    const searchInputRef = useRef(null);
    const [components, setComponents] = useState([]);
    const [categories, setCategories] = useState([]);
    const [componentsToShow, setComponentsToShow] = useState([]);
    const [selectedComponentMetadata, setSelectedComponentMetadata] = useState(null);
    useEffect(() => {
        setComponents(props.components);
        setComponentsToShow([...props.components]);
        setCategories(props.categories);
    }, [props.categories, props.components]);
    useEffect(() => {
        const normalizedSearch = search.trim().toLowerCase();
        const filteredComponents = components
            .filter((componentMetadata) => {
            return componentMetadata.componentType === props.componentsType;
        })
            .filter((componentMetadata) => {
            if (!normalizedSearch) {
                return true;
            }
            return (componentMetadata.title.toLowerCase().includes(normalizedSearch) ||
                componentMetadata.description
                    .toLowerCase()
                    .includes(normalizedSearch) ||
                componentMetadata.category.toLowerCase().includes(normalizedSearch));
        })
            .sort((componentA, componentB) => {
            if (!normalizedSearch) {
                return componentA.title.localeCompare(componentB.title);
            }
            const scoreDifference = getSearchScore(componentB, normalizedSearch) -
                getSearchScore(componentA, normalizedSearch);
            if (scoreDifference !== 0) {
                return scoreDifference;
            }
            return componentA.title.localeCompare(componentB.title);
        });
        setComponentsToShow(filteredComponents);
    }, [components, props.componentsType, search]);
    useEffect(() => {
        var _a;
        (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }, []);
    useEffect(() => {
        const handleKeyDown = (event) => {
            var _a;
            const target = event.target;
            const isTypingContext = Boolean(target &&
                (target.tagName === "INPUT" ||
                    target.tagName === "TEXTAREA" ||
                    target.getAttribute("contenteditable") === "true"));
            if (event.key === "/" &&
                !event.metaKey &&
                !event.ctrlKey &&
                !event.altKey &&
                !isTypingContext) {
                event.preventDefault();
                (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
            }
        };
        window.addEventListener("keydown", handleKeyDown);
        return () => {
            window.removeEventListener("keydown", handleKeyDown);
        };
    }, []);
    const hasSearchTerm = search.trim().length > 0;
    const normalizedSearch = search.trim().toLowerCase();
    const totalComponentCount = components.length;
    const componentTypeLabel = `${props.componentsType.toLowerCase()}${totalComponentCount === 1 ? "" : "s"}`;
    const suggestedCategories = categories
        .filter((category) => {
        return components.some((componentMetadata) => {
            return componentMetadata.category === category.name;
        });
    })
        .slice(0, 4);
    const renderHighlightedText = (text, markClassName) => {
        if (!hasSearchTerm) {
            return text;
        }
        const highlightedParts = text.split(new RegExp(`(${escapeRegExp(search.trim())})`, "ig"));
        return (React.createElement(React.Fragment, null, highlightedParts.map((part, index) => {
            if (part.toLowerCase() === normalizedSearch) {
                return (React.createElement("mark", { key: `${part}-${index}`, className: markClassName || "rounded bg-amber-100 px-0.5 text-current" }, part));
            }
            return (React.createElement(React.Fragment, { key: `${part}-${index}` }, part));
        })));
    };
    return (React.createElement(SideOver, { submitButtonText: "Add to Workflow", title: `Add ${props.componentsType}`, description: `Choose a ${props.componentsType.toLowerCase()} to add to your workflow.`, onClose: props.onCloseModal, submitButtonDisabled: !selectedComponentMetadata, onSubmit: () => {
            return (selectedComponentMetadata &&
                props.onComponentClick(selectedComponentMetadata));
        } },
        React.createElement(React.Fragment, null,
            React.createElement("div", { className: "flex flex-col h-full" },
                React.createElement("div", { className: "mt-4 mb-5" },
                    React.createElement("div", { className: "rounded-3xl border border-slate-200 bg-gradient-to-br from-white via-indigo-50 to-slate-50 p-3 shadow-sm" },
                        React.createElement("div", { className: "mb-3 flex items-start justify-between gap-3" },
                            React.createElement("div", { className: "min-w-0" },
                                React.createElement("label", { htmlFor: "workflow-component-search", className: "block text-xs font-semibold uppercase tracking-wide text-slate-500" },
                                    "Search ",
                                    componentTypeLabel),
                                React.createElement("p", { className: "mt-1 text-sm text-slate-600" }, hasSearchTerm
                                    ? "Showing the closest matches first across title, description, and category."
                                    : `Find the right ${props.componentsType.toLowerCase()} by name, category, or the job you need it to do.`)),
                            React.createElement("div", { className: "inline-flex flex-shrink-0 items-center rounded-full bg-white/90 px-3 py-1 text-xs font-semibold text-slate-500 ring-1 ring-slate-200" }, hasSearchTerm
                                ? `${componentsToShow.length} match${componentsToShow.length === 1 ? "" : "es"}`
                                : `${totalComponentCount} available`)),
                        React.createElement("div", { className: "relative flex items-center gap-3 rounded-2xl border border-slate-200 bg-white/90 px-3 py-3 shadow-sm transition-all duration-200 hover:border-slate-300 focus-within:border-indigo-500 focus-within:ring-4 focus-within:ring-indigo-100" },
                            React.createElement("div", { className: "flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-white via-indigo-50 to-sky-100 text-indigo-600 ring-1 ring-indigo-100 shadow-sm" },
                                React.createElement(Icon, { icon: IconProp.Search, className: "h-4 w-4" })),
                            React.createElement("div", { className: "min-w-0 flex-1" },
                                React.createElement("input", { id: "workflow-component-search", ref: searchInputRef, type: "text", value: search, placeholder: `Search ${componentTypeLabel} by name, description, or category`, autoComplete: "off", className: "block w-full border-0 bg-transparent p-0 text-base font-semibold text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-0", onChange: (event) => {
                                        setSearch(event.target.value);
                                    }, onKeyDown: (event) => {
                                        var _a;
                                        if (event.key === "Escape" && hasSearchTerm) {
                                            setSearch("");
                                            (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                                        }
                                    } }),
                                React.createElement("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-xs text-slate-500" },
                                    React.createElement("span", null, hasSearchTerm
                                        ? `Showing ${componentsToShow.length} of ${totalComponentCount} ${componentTypeLabel}.`
                                        : "Searches title, description, and category."),
                                    !hasSearchTerm && (React.createElement("span", { className: "hidden items-center gap-1 rounded-full bg-slate-100 px-2 py-1 font-medium text-slate-500 sm:inline-flex" },
                                        React.createElement("kbd", { className: "rounded bg-white px-1.5 py-0.5 text-[10px] font-semibold text-slate-500 ring-1 ring-slate-200" }, "/"),
                                        "Quick focus")),
                                    hasSearchTerm && (React.createElement("span", { className: "hidden items-center gap-1 rounded-full bg-indigo-50 px-2 py-1 font-medium text-indigo-600 sm:inline-flex" },
                                        React.createElement("kbd", { className: "rounded bg-white px-1.5 py-0.5 text-[10px] font-semibold text-indigo-600 ring-1 ring-indigo-100" }, "Esc"),
                                        "Clear search")))),
                            hasSearchTerm && (React.createElement("div", { className: "flex flex-shrink-0 items-center gap-2" },
                                React.createElement("button", { type: "button", className: "inline-flex items-center gap-1 rounded-full bg-slate-900 px-3 py-1.5 text-xs font-medium text-white shadow-sm transition-colors duration-150 hover:bg-slate-700", onClick: () => {
                                        var _a;
                                        setSearch("");
                                        (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                                    } },
                                    React.createElement(Icon, { icon: IconProp.Close, className: "h-3 w-3" }),
                                    "Clear")))),
                        suggestedCategories.length > 0 && (React.createElement("div", { className: "mt-3 flex flex-wrap items-center gap-2" },
                            React.createElement("span", { className: "text-xs font-medium text-slate-500" }, "Quick filters:"),
                            suggestedCategories.map((category) => {
                                const isActive = normalizedSearch === category.name.toLowerCase();
                                return (React.createElement("button", { key: category.name, type: "button", onClick: () => {
                                        var _a;
                                        setSearch(category.name);
                                        (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                                    }, className: `inline-flex items-center gap-1 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors duration-150 ${isActive
                                        ? "border-indigo-200 bg-indigo-50 text-indigo-700"
                                        : "border-slate-200 bg-white text-slate-600 hover:border-slate-300 hover:bg-slate-50"}` },
                                    React.createElement(Icon, { icon: category.icon, className: "h-3 w-3" }),
                                    category.name));
                            }))))),
                React.createElement("div", { className: "overflow-y-auto overflow-x-hidden flex-1" },
                    !componentsToShow ||
                        (componentsToShow.length === 0 && (React.createElement("div", { className: "mt-20 flex w-full flex-col items-center justify-center gap-4 px-4" },
                            React.createElement("div", { className: "max-w-2xl" },
                                React.createElement(ErrorMessage, { message: "No components that match your search. If you are looking for an integration that does not exist currently - you can use Custom Code or API component to build anything you like." })),
                            hasSearchTerm && (React.createElement("button", { type: "button", className: "inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-600 shadow-sm transition-colors duration-150 hover:bg-slate-50 hover:text-slate-800", onClick: () => {
                                    var _a;
                                    setSearch("");
                                    (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                                } },
                                React.createElement(Icon, { icon: IconProp.Close, className: "h-3.5 w-3.5" }),
                                "Reset search"))))),
                    categories &&
                        categories.length > 0 &&
                        categories.map((category, i) => {
                            const categoryComponents = componentsToShow.filter((componentMetadata) => {
                                return componentMetadata.category === category.name;
                            });
                            if (categoryComponents.length === 0) {
                                return React.createElement("div", { key: i });
                            }
                            return (React.createElement("div", { key: i, className: "mb-6" },
                                React.createElement("div", { className: "flex items-center gap-2 mb-3 px-1" },
                                    React.createElement("div", { className: "flex items-center justify-center rounded-md", style: {
                                            width: "28px",
                                            height: "28px",
                                            backgroundColor: "#f1f5f9",
                                        } },
                                        React.createElement(Icon, { icon: category.icon, className: "h-4 w-4 text-gray-500" })),
                                    React.createElement("div", null,
                                        React.createElement("h4", { className: "text-sm font-semibold text-gray-700 leading-tight" }, category.name),
                                        React.createElement("p", { className: "text-xs text-gray-400 leading-tight" }, category.description))),
                                React.createElement("div", { className: "grid grid-cols-1 gap-2" }, categoryComponents.map((componentMetadata, j) => {
                                    const isSelected = selectedComponentMetadata !== null &&
                                        selectedComponentMetadata.id ===
                                            componentMetadata.id;
                                    return (React.createElement("div", { key: j, onClick: () => {
                                            setSelectedComponentMetadata(componentMetadata);
                                        }, className: "cursor-pointer transition-all duration-150", style: {
                                            padding: "0.75rem",
                                            borderRadius: "10px",
                                            border: isSelected
                                                ? "2px solid #6366f1"
                                                : "1px solid #e2e8f0",
                                            backgroundColor: isSelected
                                                ? "#eef2ff"
                                                : "#ffffff",
                                            display: "flex",
                                            alignItems: "flex-start",
                                            gap: "0.75rem",
                                            boxShadow: isSelected
                                                ? "0 0 0 3px rgba(99, 102, 241, 0.1)"
                                                : "0 1px 2px 0 rgba(0, 0, 0, 0.03)",
                                        } },
                                        React.createElement("div", { style: {
                                                width: "36px",
                                                height: "36px",
                                                borderRadius: "8px",
                                                backgroundColor: isSelected
                                                    ? "#6366f1"
                                                    : "#f1f5f9",
                                                display: "flex",
                                                alignItems: "center",
                                                justifyContent: "center",
                                                flexShrink: 0,
                                                transition: "all 0.15s ease",
                                            } },
                                            React.createElement(Icon, { icon: componentMetadata.iconProp, style: {
                                                    color: isSelected ? "#ffffff" : "#64748b",
                                                    width: "1rem",
                                                    height: "1rem",
                                                } })),
                                        React.createElement("div", { style: { minWidth: 0, flex: 1 } },
                                            React.createElement("div", { className: "flex items-start justify-between gap-2" },
                                                React.createElement("p", { style: {
                                                        fontSize: "0.8125rem",
                                                        fontWeight: 600,
                                                        color: isSelected ? "#4338ca" : "#1e293b",
                                                        margin: 0,
                                                        lineHeight: "1.25rem",
                                                    } }, renderHighlightedText(componentMetadata.title, isSelected
                                                    ? "rounded bg-white/80 px-0.5 text-current"
                                                    : "rounded bg-amber-100 px-0.5 text-current")),
                                                hasSearchTerm && (React.createElement("span", { className: `mt-0.5 inline-flex flex-shrink-0 rounded-full px-2 py-0.5 text-[11px] font-medium ${isSelected
                                                        ? "bg-white/80 text-indigo-700"
                                                        : "bg-slate-100 text-slate-500"}` }, renderHighlightedText(componentMetadata.category, isSelected
                                                    ? "rounded bg-indigo-100 px-0.5 text-current"
                                                    : "rounded bg-white px-0.5 text-current")))),
                                            React.createElement("p", { style: {
                                                    fontSize: "0.75rem",
                                                    color: isSelected ? "#6366f1" : "#94a3b8",
                                                    margin: 0,
                                                    marginTop: "2px",
                                                    lineHeight: "1rem",
                                                    display: "-webkit-box",
                                                    WebkitLineClamp: 2,
                                                    WebkitBoxOrient: "vertical",
                                                    overflow: "hidden",
                                                } }, renderHighlightedText(componentMetadata.description, isSelected
                                                ? "rounded bg-white/80 px-0.5 text-current"
                                                : "rounded bg-amber-100 px-0.5 text-current"))),
                                        isSelected && (React.createElement("div", { style: {
                                                width: "20px",
                                                height: "20px",
                                                borderRadius: "50%",
                                                backgroundColor: "#6366f1",
                                                display: "flex",
                                                alignItems: "center",
                                                justifyContent: "center",
                                                flexShrink: 0,
                                                marginTop: "2px",
                                            } },
                                            React.createElement(Icon, { icon: IconProp.Check, style: {
                                                    color: "#ffffff",
                                                    width: "0.625rem",
                                                    height: "0.625rem",
                                                } })))));
                                }))));
                        }))))));
};
export default ComponentsModal;
//# sourceMappingURL=ComponentsModal.js.map