"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
/**
 * Vector Search Component
 *
 * A component that demonstrates using vector embeddings for semantic search
 */
const react_1 = require("react");
const useAI_js_1 = __importDefault(require("../../hooks/useAI.js"));
const vectorUtils_js_1 = require("../../utils/vectorUtils.js");
const VectorSearch = ({ items, className = '', topResults = 5, highlightMatches = true, onSelect }) => {
    // State
    const [query, setQuery] = (0, react_1.useState)('');
    const [searchResults, setSearchResults] = (0, react_1.useState)([]);
    const [searchPerformed, setSearchPerformed] = (0, react_1.useState)(false);
    const [itemsWithEmbeddings, setItemsWithEmbeddings] = (0, react_1.useState)([]);
    const [isIndexing, setIsIndexing] = (0, react_1.useState)(false);
    // Get AI capabilities from our hook
    const { generateEmbeddings, isLoading, error } = (0, useAI_js_1.default)({
        initialConfig: {
            model: 'text-embedding-ada-002'
        }
    });
    // Generate embeddings for all items
    const indexItems = (0, react_1.useCallback)(async () => {
        if (isIndexing || items.every(item => !!item.embedding))
            return;
        try {
            setIsIndexing(true);
            // Filter items that don't have embeddings yet
            const itemsToEmbed = items.filter(item => !item.embedding);
            if (itemsToEmbed.length === 0) {
                setItemsWithEmbeddings(items);
                return;
            }
            // Prepare content for embedding
            const textsToEmbed = itemsToEmbed.map(item => item.content);
            // Generate embeddings
            const embeddings = await generateEmbeddings(textsToEmbed);
            // Combine original items with new embeddings
            const updatedItems = [...items];
            let embeddingIndex = 0;
            for (let i = 0; i < updatedItems.length; i++) {
                if (!updatedItems[i].embedding) {
                    updatedItems[i] = {
                        ...updatedItems[i],
                        embedding: embeddings[embeddingIndex]
                    };
                    embeddingIndex++;
                }
            }
            setItemsWithEmbeddings(updatedItems);
        }
        catch (err) {
            console.error('Error generating embeddings:', err);
        }
        finally {
            setIsIndexing(false);
        }
    }, [items, isIndexing, generateEmbeddings]);
    // Perform vector search
    const performSearch = (0, react_1.useCallback)(async () => {
        if (!query.trim() || isLoading)
            return;
        try {
            // Make sure items are indexed
            if (itemsWithEmbeddings.length === 0) {
                await indexItems();
            }
            // Generate embedding for the query
            const [queryEmbedding] = await generateEmbeddings([query]);
            // Calculate similarity scores
            const results = itemsWithEmbeddings
                .map(item => ({
                ...item,
                score: item.embedding
                    ? (0, vectorUtils_js_1.cosineSimilarity)(queryEmbedding, item.embedding)
                    : 0
            }))
                .sort((a, b) => b.score - a.score)
                .slice(0, topResults);
            setSearchResults(results);
            setSearchPerformed(true);
        }
        catch (err) {
            console.error('Search error:', err);
        }
    }, [query, isLoading, itemsWithEmbeddings, indexItems, generateEmbeddings, topResults]);
    // Handle query change
    const handleQueryChange = (e) => {
        setQuery(e.target.value);
    };
    // Handle search submission
    const handleSearchSubmit = (e) => {
        e.preventDefault();
        performSearch();
    };
    // Handle item selection
    const handleItemClick = (item) => {
        if (onSelect) {
            onSelect(item);
        }
    };
    // Highlight matching terms
    const highlightText = (text, searchQuery) => {
        if (!highlightMatches || !searchQuery.trim()) {
            return text;
        }
        const parts = text.split(new RegExp(`(${searchQuery})`, 'gi'));
        return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: parts.map((part, index) => part.toLowerCase() === searchQuery.toLowerCase()
                ? (0, jsx_runtime_1.jsx)("mark", { className: "bg-yellow-200", children: part }, index)
                : part) }));
    };
    return ((0, jsx_runtime_1.jsxs)("div", { className: `bg-white rounded-lg shadow-md ${className}`, children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 border-b", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-xl font-semibold", children: "Semantic Search" }), (0, jsx_runtime_1.jsx)("p", { className: "text-gray-500", children: "Search using vector embeddings for more accurate results" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4", children: [itemsWithEmbeddings.length === 0 && !isIndexing && ((0, jsx_runtime_1.jsxs)("button", { onClick: indexItems, className: "mb-4 px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 w-full", disabled: isIndexing || isLoading, children: ["Index ", items.length, " Items"] })), isIndexing && ((0, jsx_runtime_1.jsxs)("div", { className: "mb-4 p-3 bg-blue-50 rounded-md text-center", children: [(0, jsx_runtime_1.jsxs)("p", { className: "text-blue-700", children: ["Generating embeddings for ", items.length, " items..."] }), (0, jsx_runtime_1.jsx)("div", { className: "mt-2 w-full bg-gray-200 rounded-full h-2.5", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-blue-600 h-2.5 rounded-full animate-pulse w-full" }) })] })), (0, jsx_runtime_1.jsx)("form", { onSubmit: handleSearchSubmit, className: "mb-6", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex", children: [(0, jsx_runtime_1.jsx)("input", { type: "text", value: query, onChange: handleQueryChange, placeholder: "Enter your search query...", className: "flex-grow p-2 border rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500", disabled: isLoading || isIndexing }), (0, jsx_runtime_1.jsx)("button", { type: "submit", className: "px-4 py-2 bg-blue-500 text-white rounded-r-md hover:bg-blue-600 disabled:bg-blue-300", disabled: !query.trim() || isLoading || isIndexing, children: isLoading ? 'Searching...' : 'Search' })] }) }), error && ((0, jsx_runtime_1.jsxs)("div", { className: "mb-4 p-3 bg-red-100 text-red-800 rounded-md", children: [(0, jsx_runtime_1.jsxs)("p", { className: "font-semibold", children: ["Error: ", error.code] }), (0, jsx_runtime_1.jsx)("p", { children: error.message })] })), searchPerformed && ((0, jsx_runtime_1.jsxs)("div", { className: "results", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-lg font-semibold mb-3", children: ["Results ", searchResults.length > 0 ? `(${searchResults.length})` : ''] }), searchResults.length === 0 ? ((0, jsx_runtime_1.jsx)("p", { className: "text-gray-500", children: "No results found. Try a different query." })) : ((0, jsx_runtime_1.jsx)("ul", { className: "divide-y", children: searchResults.map(item => ((0, jsx_runtime_1.jsxs)("li", { className: "py-3 cursor-pointer hover:bg-gray-50", onClick: () => handleItemClick(item), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-start", children: [(0, jsx_runtime_1.jsx)("h4", { className: "font-medium text-lg", children: highlightText(item.title, query) }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm bg-blue-100 text-blue-800 px-2 py-1 rounded", children: [(item.score * 100).toFixed(1), "% match"] })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-gray-700 mt-1 line-clamp-2", children: highlightText(item.content.substring(0, 150) + '...', query) })] }, item.id))) }))] }))] })] }));
};
exports.default = VectorSearch;
//# sourceMappingURL=VectorSearch.js.map