/**
 * History Component
 * Manages the display and interaction with research history
 */
(function() {
    // DOM Elements
    let historyContainer = null;
    let searchInput = null;
    let clearHistoryBtn = null;
    let historyEmptyMessage = null;

    // Component state
    let historyItems = [];
    let filteredItems = [];
    let inputDebounceTimer = null;
    let semanticDebounceTimer = null;
    const SM = (typeof LDR_CONSTANTS !== 'undefined' && LDR_CONSTANTS.SEARCH_MODE) || { HYBRID: 'hybrid', TEXT: 'text', SEMANTIC: 'semantic' };
    let searchMode = SM.HYBRID;
    let hybridSearchId = 0;
    let semanticSearchId = 0;

    // Security: local escapeHtml to prevent XSS in innerHTML assignments
    // bearer:disable javascript_lang_manual_html_sanitization
    const esc = window.escapeHtml || (s => String(s || '').replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":"&#39;"})[m]));

    // Shared semantic search utilities (from semantic_search.js)
    const renderSnippet = (window.SemanticSearch && window.SemanticSearch.renderSnippet) || (md => esc(md || ''));

    // Fallback UI utilities in case main UI utils aren't loaded
    const uiUtils = {
        showSpinner(container, message) {
            if (window.ui && window.ui.showSpinner) {
                window.ui.showSpinner(container, message);
                return;
            }

            // Fallback implementation
            if (!container) container = document.body;
            // Security: escapeHtml applied to message before innerHTML insertion
            const spinnerHtml = `
                <div class="ldr-loading-spinner ldr-centered">
                    <div class="ldr-spinner"></div>
                    ${message ? `<div class="ldr-spinner-message">${esc(message)}</div>` : ''}
                </div>
            `;
            // bearer:disable javascript_lang_dangerous_insert_html
            // eslint-disable-next-line no-unsanitized/property -- audited 2026-03-28: variable built from escaped/numeric values above
            container.innerHTML = spinnerHtml;
        },

        hideSpinner(container) {
            if (window.ui && window.ui.hideSpinner) {
                window.ui.hideSpinner(container);
                return;
            }

            // Fallback implementation
            if (!container) container = document.body;
            const spinner = container.querySelector('.ldr-loading-spinner');
            if (spinner) {
                spinner.remove();
            }
        },

        showError(message) {
            if (window.ui && window.ui.showError) {
                window.ui.showError(message);
                return;
            }

            // Fallback implementation
            SafeLogger.error(message);
            alert(message);
        },

        showMessage(message) {
            if (window.ui && window.ui.showMessage) {
                window.ui.showMessage(message);
                return;
            }

            // Fallback implementation
            SafeLogger.log(message);
            alert(message);
        }
    };

    // Fallback API utilities
    const apiUtils = {
        async getResearchHistory() {
            if (window.api && window.api.getResearchHistory) {
                return window.api.getResearchHistory();
            }

            // Fallback implementation
            try {
                const response = await fetch(URLS.API.HISTORY);
                if (!response.ok) {
                    throw new Error(`API Error: ${response.status} ${response.statusText}`);
                }
                return await response.json();
            } catch (error) {
                SafeLogger.error('API Error:', error);
                throw error;
            }
        },

        async deleteResearch(researchId) {
            if (window.api && window.api.deleteResearch) {
                return window.api.deleteResearch(researchId);
            }

            // Fallback implementation
            try {
                const csrfToken = window.api ? window.api.getCsrfToken() : '';
                const response = await fetch(URLBuilder.deleteResearch(researchId), {
                    method: 'DELETE',
                    headers: {
                        ...(csrfToken ? { 'X-CSRFToken': csrfToken } : {})
                    }
                });
                if (!response.ok) {
                    throw new Error(`API Error: ${response.status} ${response.statusText}`);
                }
                return await response.json();
            } catch (error) {
                SafeLogger.error('API Error:', error);
                throw error;
            }
        },

        async clearResearchHistory() {
            if (window.api && window.api.clearResearchHistory) {
                return window.api.clearResearchHistory();
            }

            // Fallback implementation
            try {
                const csrfToken = window.api ? window.api.getCsrfToken() : '';
                const response = await fetch(URLS.API.CLEAR_HISTORY, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        ...(csrfToken ? { 'X-CSRFToken': csrfToken } : {})
                    },
                    body: JSON.stringify({})
                });
                if (!response.ok) {
                    throw new Error(`API Error: ${response.status} ${response.statusText}`);
                }
                return await response.json();
            } catch (error) {
                SafeLogger.error('API Error:', error);
                throw error;
            }
        }
    };

    /**
     * Initialize the history component
     */
    function initializeHistory() {
        // Get DOM elements
        historyContainer = document.getElementById('history-items');
        searchInput = document.getElementById('history-search');
        clearHistoryBtn = document.getElementById('clear-history-btn');
        historyEmptyMessage = document.getElementById('history-empty-message');

        if (!historyContainer) {
            SafeLogger.error('Required DOM elements not found for history component');
            return;
        }

        // Set up event listeners
        setupEventListeners();

        // Load history data
        loadHistoryData();

        SafeLogger.log('History component initialized');
    }

    /**
     * Set up event listeners
     */
    function setupEventListeners() {
        // Debounced search input
        if (searchInput) {
            searchInput.addEventListener('input', () => {
                clearTimeout(inputDebounceTimer);
                inputDebounceTimer = setTimeout(handleSearchInput, 250);
            });
        }

        // Search mode dropdown
        const modeMenu = document.getElementById('search-mode-menu');
        if (modeMenu) {
            modeMenu.addEventListener('click', (e) => {
                const item = e.target.closest('.dropdown-item');
                if (!item) return;
                e.preventDefault();

                const mode = item.dataset.mode;
                if (!mode || mode === searchMode) return;

                searchMode = mode;

                // Update active state
                modeMenu.querySelectorAll('.dropdown-item').forEach(el => el.classList.remove('active'));
                item.classList.add('active');

                // Update button label
                const btn = document.getElementById('search-mode-btn');
                const iconMap = { hybrid: 'fa-brain', text: 'fa-font', semantic: 'fa-brain' };
                const labelMap = { hybrid: 'AI Hybrid', text: 'Text Only', semantic: 'AI Only' };
                const placeholders = { hybrid: 'Search titles + content...', text: 'Filter history by title...', semantic: 'Search content with AI...' };
                if (btn && labelMap[mode]) {
                    window.safeUpdateButton(btn, iconMap[mode], ' ' + labelMap[mode]);
                }
                if (searchInput) searchInput.placeholder = placeholders[mode];

                handleSearchInput();
            });
        }

        // Clear history button
        if (clearHistoryBtn) {
            clearHistoryBtn.addEventListener('click', handleClearHistory);
        }

        // Single delegated handler for all history item interactions
        if (historyContainer) {
            historyContainer.addEventListener('click', function(e) {
                const itemEl = e.target.closest('.ldr-history-item');
                if (!itemEl) return;
                const itemId = itemEl.dataset.id;
                const itemData = historyItems.find(h => String(h.id) === itemId);

                // For semantic-only items not in historyItems, handle View + item click
                if (!itemData) {
                    if (e.target.closest('.ldr-view-btn') || !e.target.closest('button')) {
                        URLValidator.safeAssign(window.location, 'href', URLBuilder.resultsPage(itemId));
                    }
                    return;
                }

                if (e.target.closest('.ldr-delete-item-btn')) {
                    handleDeleteItem(itemId);
                } else if (e.target.closest('.ldr-view-btn')) {
                    URLValidator.safeAssign(window.location, 'href', URLBuilder.resultsPage(itemId));
                } else if (e.target.closest('.ldr-library-btn')) {
                    URLValidator.safeAssign(window.location, 'href', `${URLS.PAGES.LIBRARY}?research=${encodeURIComponent(itemId)}`);
                } else if (e.target.closest('.ldr-subscribe-btn')) {
                    handleSubscribe(itemData);
                } else if (e.target.closest('.ldr-rerun-btn')) {
                    handleRerun(itemData);
                } else if (ResearchStates.isCompleted(itemData.status)) {
                    // Item-level click (navigate to results/progress)
                    URLValidator.safeAssign(window.location, 'href', URLBuilder.resultsPage(itemId));
                } else {
                    URLValidator.safeAssign(window.location, 'href', URLBuilder.progressPage(itemId));
                }
            });
        }
    }

    /**
     * Load history data from API
     */
    async function loadHistoryData() {
        // Show loading state
        uiUtils.showSpinner(historyContainer, 'Loading research history...');

        try {
            // Get history items
            const response = await apiUtils.getResearchHistory();

            if (response && Array.isArray(response.items)) {
                historyItems = response.items;
                filteredItems = [...historyItems];

                // Render history items
                renderHistoryItems();
            } else {
                throw new Error('Invalid response format');
            }
        } catch (error) {
            SafeLogger.error('Error loading history:', error);
            uiUtils.hideSpinner(historyContainer);
            uiUtils.showError('Error loading history: ' + error.message);
        }
    }

    /**
     * Render history items
     */
    function renderHistoryItems() {
        // Hide spinner
        uiUtils.hideSpinner(historyContainer);

        // Clear container
        historyContainer.innerHTML = '';

        // Show empty message if no items
        if (filteredItems.length === 0) {
            if (historyEmptyMessage) {
                historyEmptyMessage.style.display = 'block';
            } else {
                // eslint-disable-next-line no-unsanitized/property -- audited 2026-03-28: all interpolations use escapeHtml/esc, numeric coercion, or hardcoded strings
                historyContainer.innerHTML = `
                    <div class="ldr-empty-state">
                        <i class="fas fa-history ldr-empty-icon"></i>
                        <p>No research history found.</p>
                        ${searchInput && searchInput.value ? '<p>Try adjusting your search query.</p>' : ''}
                    </div>
                `;
            }

            if (clearHistoryBtn) {
                clearHistoryBtn.style.display = 'none';
            }
            return;
        }

        // Hide empty message
        if (historyEmptyMessage) {
            historyEmptyMessage.style.display = 'none';
        }

        // Show clear button
        if (clearHistoryBtn) {
            clearHistoryBtn.style.display = 'inline-block';
        }

        // Create items using DocumentFragment for batch DOM insertion
        const fragment = document.createDocumentFragment();
        filteredItems.forEach(item => {
            fragment.appendChild(createHistoryItemElement(item));
        });
        historyContainer.appendChild(fragment);
    }

    /**
     * Format date safely using the formatter if available
     */
    function formatDate(dateStr) {
        if (window.formatting && window.formatting.formatDate) {
            return window.formatting.formatDate(dateStr);
        }

        // Simple fallback date formatting
        try {
            const date = new Date(dateStr);
            return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
        } catch {
            return dateStr;
        }
    }

    /**
     * Format status safely using ResearchStates helper
     */
    function formatStatus(status) {
        return ResearchStates.formatStatus(status);
    }

    /**
     * Format mode safely using the formatter if available
     */
    function formatMode(mode) {
        if (window.formatting && window.formatting.formatMode) {
            return window.formatting.formatMode(mode);
        }

        // Simple fallback formatting
        const modeMap = {
            'quick': 'Quick Summary',
            'detailed': 'Detailed Report'
        };

        return modeMap[mode] || mode;
    }

    /**
     * Create a history item element
     * @param {Object} item - The history item data
     * @param {Object|null} semanticMatch - Optional semantic match data {similarity, snippet}
     * @returns {HTMLElement} The history item element
     */
    function createHistoryItemElement(item, semanticMatch) {
        const itemEl = document.createElement('div');
        itemEl.className = 'ldr-history-item';
        if (semanticMatch) itemEl.classList.add('ldr-history-item--semantic');
        itemEl.dataset.id = item.id;

        // Format date
        const formattedDate = formatDate(item.created_at);

        // Get a display title (use query if title is not available)
        const displayTitle = item.title || formatTitleFromQuery(item.query);

        // Status class - convert in_progress to in-progress for CSS
        const statusClass = item.status ? item.status.replace('_', '-') : '';

        // Check if this is a news-related research
        const isNewsItem = item.metadata && item.metadata.is_news_search;

        // AI match badge + snippet rows (for Tier 1 items)
        const aiMatchHtml = semanticMatch ? `
            <div class="ldr-history-item-ai-match">
                <span class="ldr-ai-match-badge"><i class="fas fa-brain"></i> ${esc(String(semanticMatch.similarity))}% match</span>
            </div>
            ${semanticMatch.snippet ? `<div class="ldr-history-item-snippet">${renderSnippet(semanticMatch.snippet, searchInput ? searchInput.value.trim() : '')}</div>` : ''}
        ` : '';

        // bearer:disable javascript_lang_dangerous_insert_html
        // eslint-disable-next-line no-unsanitized/property -- audited 2026-03-28: variable built from escaped/numeric values above
        itemEl.innerHTML = `
            <div class="ldr-history-item-header">
                <div class="ldr-history-item-title">${esc(displayTitle)}</div>
                <div class="ldr-history-item-status ldr-status-${esc(statusClass)}">${esc(formatStatus(item.status))}</div>
            </div>
            ${aiMatchHtml}
            <div class="ldr-history-item-meta">
                <div class="ldr-history-item-date">${esc(formattedDate)}</div>
                <div class="ldr-history-item-mode">${esc(formatMode(item.mode))}</div>
                ${isNewsItem ? '<span class="ldr-news-indicator"><i class="fas fa-newspaper"></i> News</span>' : ''}
            </div>
            <div class="ldr-history-item-actions">
                ${ResearchStates.isCompleted(item.status) ?
                    `<button class="btn btn-sm ldr-btn-outline ldr-view-btn">
                        <i class="fas fa-eye"></i><span> View</span>
                    </button>` : ''}
                ${ResearchStates.isCompleted(item.status) && item.document_count > 0 ?
                    `<button class="btn btn-sm ldr-btn-outline ldr-library-btn">
                        <i class="fas fa-book"></i><span> Library (${esc(String(item.document_count))})</span>
                    </button>` : ''}
                ${isNewsItem && ResearchStates.isCompleted(item.status) ?
                    `<button class="btn btn-sm ldr-btn-outline ldr-subscribe-btn" data-research-id="${esc(item.id)}" data-query="${esc(encodeURIComponent(item.query))}">
                        <i class="fas fa-bell"></i><span> Subscribe</span>
                    </button>` : ''}
                ${ResearchStates.isCompleted(item.status) ?
                    `<button class="btn btn-sm ldr-btn-outline ldr-rerun-btn" title="Re-run this research">
                        <i class="fas fa-redo"></i><span> Re-run</span>
                    </button>` : ''}
                <button class="btn btn-sm ldr-btn-outline ldr-delete-item-btn">
                    <i class="fas fa-trash-alt"></i>
                </button>
            </div>
        `;

        return itemEl;
    }

    /**
     * Create a semantic-only item element (Tier 3).
     * Tries to find the full history item; if found, renders full card with semantic badge.
     * Otherwise renders a simplified card with View button only.
     */
    function createSemanticOnlyElement(semanticResult) {
        const historyItem = historyItems.find(h => String(h.id) === String(semanticResult.research_id));
        const semanticMatch = {
            similarity: semanticResult.similarity,
            snippet: semanticResult.snippet || ''
        };

        if (historyItem) {
            return createHistoryItemElement(historyItem, semanticMatch);
        }

        // Simplified card — no full history data available
        const itemEl = document.createElement('div');
        itemEl.className = 'ldr-history-item ldr-history-item--semantic-only';
        itemEl.dataset.id = semanticResult.research_id;

        const displayTitle = semanticResult.research_title || semanticResult.title || 'Untitled Research';
        let dateStr = '';
        if (semanticResult.research_created_at) {
            try {
                dateStr = new Date(semanticResult.research_created_at).toLocaleDateString();
            } catch {
                dateStr = '';
            }
        }

        // bearer:disable javascript_lang_dangerous_insert_html
        // eslint-disable-next-line no-unsanitized/property -- audited 2026-03-28: all interpolations use escapeHtml/esc, numeric coercion, or hardcoded strings
        itemEl.innerHTML = `
            <div class="ldr-history-item-header">
                <div class="ldr-history-item-title">${esc(displayTitle)}</div>
            </div>
            <div class="ldr-history-item-ai-match">
                <span class="ldr-ai-match-badge"><i class="fas fa-brain"></i> ${esc(String(semanticResult.similarity))}% match</span>
            </div>
            ${semanticResult.snippet ? `<div class="ldr-history-item-snippet">${renderSnippet(semanticResult.snippet, searchInput ? searchInput.value.trim() : '')}</div>` : ''}
            <div class="ldr-history-item-meta">
                ${dateStr ? `<div class="ldr-history-item-date">${esc(dateStr)}</div>` : ''}
            </div>
            <div class="ldr-history-item-actions">
                <button class="btn btn-sm ldr-btn-outline ldr-view-btn">
                    <i class="fas fa-eye"></i><span> View</span>
                </button>
            </div>
        `;

        return itemEl;
    }

    // Shared tiered merge from semantic_search.js
    const buildTieredResults = (window.SemanticSearch && window.SemanticSearch.buildTieredResults) || function() { return { tier1: [], tier2: [], tier3: [] }; };

    /**
     * Render merged tiered results into the history container.
     */
    function renderMergedResults(tiered) {
        if (!historyContainer) return;

        const { tier1, tier2, tier3 } = tiered;
        const totalCount = tier1.length + tier2.length + tier3.length;

        if (totalCount === 0) {
            historyContainer.innerHTML = `
                <div class="ldr-empty-state">
                    <i class="fas fa-history ldr-empty-icon"></i>
                    <p>No research history found.</p>
                    <p>Try adjusting your search query.</p>
                </div>
            `;
            return;
        }

        // Brief settling transition
        historyContainer.classList.add('ldr-results-settling');

        const fragment = document.createDocumentFragment();

        // Tier 1: both text + semantic
        for (const entry of tier1) {
            fragment.appendChild(createHistoryItemElement(entry.historyItem, entry.semanticMatch));
        }

        // Tier 2: text-only
        for (const entry of tier2) {
            fragment.appendChild(createHistoryItemElement(entry.historyItem));
        }

        // Tier 3: semantic-only (with divider)
        if (tier3.length > 0) {
            const divider = document.createElement('div');
            divider.className = 'ldr-hybrid-divider';
            divider.textContent = 'Also found in content';
            fragment.appendChild(divider);

            for (const entry of tier3) {
                fragment.appendChild(createSemanticOnlyElement(entry.semanticResult));
            }
        }

        historyContainer.innerHTML = '';
        historyContainer.appendChild(fragment);

        // Remove settling class after browser has painted the 0.6 opacity frame
        requestAnimationFrame(() => {
            requestAnimationFrame(() => {
                historyContainer.classList.remove('ldr-results-settling');
            });
        });
    }

    /**
     * Handle subscribe button click
     * @param {Object} item - The research item
     */
    async function handleSubscribe(item) {
        // Redirect to subscription form with pre-filled query
        const params = new URLSearchParams({
            query: item.query,
            name: item.query.substring(0, 50),
            source_id: item.id
        });
        URLValidator.safeAssign(window.location, 'href', `/news/subscriptions/new?${params.toString()}`);
    }

    /**
     * Handle re-run button click
     * Stores research config in sessionStorage and navigates to research page
     * @param {Object} item - The research item to re-run
     */
    function handleRerun(item) {
        if (!item.query) return;
        try {
            const rerunConfig = {
                query: item.query,
                mode: item.mode
            };
            sessionStorage.setItem('rerunConfig', JSON.stringify(rerunConfig));
        } catch (e) {
            SafeLogger.warn('Could not save rerun config:', e);
        }
        URLValidator.safeAssign(window.location, 'href', '/');
    }

    // Modal-based subscription removed - now redirects to dedicated form page

    // Folder loading removed - handled by dedicated form page

    // Subscription creation removed - handled by dedicated form page

    // Subscription status update removed - handled by dedicated form page

    /**
     * Format a title from a query string
     * Truncates long queries and adds ellipsis
     * @param {string} query - The query string
     * @returns {string} Formatted title
     */
    function formatTitleFromQuery(query) {
        if (!query) return 'Untitled Research';

        // Truncate long queries
        if (query.length > 60) {
            return query.substring(0, 57) + '...';
        }

        return query;
    }

    /**
     * Run text filter on historyItems and return the filtered list
     */
    function runTextFilter(searchTerm) {
        const lowerTerm = searchTerm.toLowerCase();
        return historyItems.filter(item => {
            const titleMatch = item.title ?
                item.title.toLowerCase().includes(lowerTerm) :
                false;
            const queryMatch = item.query ?
                item.query.toLowerCase().includes(lowerTerm) :
                false;
            return titleMatch || queryMatch;
        });
    }

    /**
     * Handle search input — text, semantic, or hybrid depending on mode
     */
    function handleSearchInput() {
        if (!searchInput) return;
        // Clean up stale hybrid loading indicator on any mode change/re-entry
        const staleIndicator = document.getElementById('hybrid-loading-indicator');
        if (staleIndicator) staleIndicator.remove();
        const searchTerm = searchInput.value.trim();

        if (!searchTerm) {
            filteredItems = [...historyItems];
            renderHistoryItems();
            return;
        }

        if (searchMode === SM.TEXT) {
            filteredItems = runTextFilter(searchTerm);
            renderHistoryItems();

        } else if (searchMode === SM.SEMANTIC) {
            clearTimeout(semanticDebounceTimer);
            const currentSemanticId = ++semanticSearchId;
            semanticDebounceTimer = setTimeout(async () => {
                if (!window.HistorySearch ||
                    typeof window.HistorySearch.semanticSearchHistory !== 'function' ||
                    typeof window.HistorySearch.renderSemanticResults !== 'function') {
                    if (historyContainer) {
                        historyContainer.innerHTML = `
                            <div class="ldr-empty-state">
                                <i class="fas fa-exclamation-triangle"></i>
                                <p>Semantic search is loading. Please try again.</p>
                            </div>
                        `;
                    }
                    return;
                }
                if (historyContainer) {
                    historyContainer.innerHTML = '<div class="ldr-loading-spinner ldr-centered"><div class="ldr-spinner"></div></div>';
                }
                try {
                    const results = await window.HistorySearch.semanticSearchHistory(searchTerm);
                    if (currentSemanticId !== semanticSearchId) return; // stale
                    if (searchMode !== SM.SEMANTIC) return; // mode changed
                    if (results && results.needsIndexing) {
                        // Race-safe: stale-id guard above ensures only the latest
                        // request reaches this assignment.
                        // eslint-disable-next-line require-atomic-updates
                        historyContainer.innerHTML = `
                            <div class="ldr-empty-state">
                                <i class="fas fa-brain"></i>
                                <p>No research indexed yet. Use the "Index All" button above to enable semantic search.</p>
                            </div>
                        `;
                        return;
                    }
                    window.HistorySearch.renderSemanticResults(results, searchTerm);
                } catch (error) {
                    SafeLogger.error('Semantic search failed:', error);
                    if (historyContainer) {
                        historyContainer.innerHTML = `
                            <div class="ldr-empty-state">
                                <i class="fas fa-exclamation-triangle"></i>
                                <p>Search failed. Please try again.</p>
                            </div>
                        `;
                    }
                }
            }, 500);

        } else if (searchMode === SM.HYBRID) {
            // 1. Instant text filter — render as Tier 2 immediately
            const textResults = runTextFilter(searchTerm);
            filteredItems = textResults;
            renderHistoryItems();

            // 2. Check if semantic search is available
            if (!window.HistorySearch ||
                typeof window.HistorySearch.getSemanticCollectionId !== 'function' ||
                !window.HistorySearch.getSemanticCollectionId()) {
                return; // Not indexed — text results only, no indicator
            }
            if (typeof window.HistorySearch.semanticSearchHistory !== 'function') {
                return;
            }

            // 3. Append loading indicator (remove stale one first)
            const existingIndicator = document.getElementById('hybrid-loading-indicator');
            if (existingIndicator) existingIndicator.remove();
            const loadingDiv = document.createElement('div');
            loadingDiv.className = 'ldr-hybrid-loading';
            loadingDiv.id = 'hybrid-loading-indicator';
            loadingDiv.innerHTML = '<div class="ldr-spinner" style="width: 16px; height: 16px; border-width: 2px;"></div> Searching content...';
            if (historyContainer) historyContainer.appendChild(loadingDiv);

            // 4. Race-condition guard
            const currentSearchId = ++hybridSearchId;

            // 5. Debounced semantic call (separate timer from input debounce)
            clearTimeout(semanticDebounceTimer);
            semanticDebounceTimer = setTimeout(async () => {
                try {
                    const results = await window.HistorySearch.semanticSearchHistory(searchTerm);
                    if (currentSearchId !== hybridSearchId) return; // stale
                    if (searchMode !== SM.HYBRID) {
                        const indicator = document.getElementById('hybrid-loading-indicator');
                        if (indicator) indicator.remove();
                        return;
                    }

                    // Remove loading indicator
                    const indicator = document.getElementById('hybrid-loading-indicator');
                    if (indicator) indicator.remove();

                    if (results && results.needsIndexing) return;

                    // Build tiered merge and re-render
                    const semanticResults = Array.isArray(results) ? results : [];
                    const tiered = buildTieredResults(textResults, semanticResults, { textIdKey: 'id', semanticIdKey: 'research_id' });
                    renderMergedResults(tiered);
                } catch (error) {
                    SafeLogger.error('Hybrid semantic search failed:', error);
                    const indicator = document.getElementById('hybrid-loading-indicator');
                    if (indicator) indicator.remove();
                }
            }, 500);
        }
    }

    /**
     * Handle delete item
     * @param {string} itemId - The item ID to delete
     */
    async function handleDeleteItem(itemId) {
        if (!confirm('Are you sure you want to delete this research? This action cannot be undone.')) {
            return;
        }

        try {
            // Delete item via API
            await apiUtils.deleteResearch(itemId);

            // Remove from arrays
            historyItems = historyItems.filter(item => String(item.id) !== itemId);
            filteredItems = filteredItems.filter(item => String(item.id) !== itemId);

            // Show success message
            uiUtils.showMessage('Research deleted successfully');

            // Re-render via handleSearchInput to preserve hybrid/semantic state
            handleSearchInput();
        } catch (error) {
            SafeLogger.error('Error deleting research:', error);
            uiUtils.showError('Error deleting research: ' + error.message);
        }
    }

    /**
     * Handle clear history
     */
    async function handleClearHistory() {
        if (!confirm('Are you sure you want to clear all research history? This action cannot be undone.')) {
            return;
        }

        try {
            // Clear history via API
            await apiUtils.clearResearchHistory();

            // Clear arrays
            historyItems = [];
            filteredItems = [];

            // Show success message
            uiUtils.showMessage('Research history cleared successfully');

            // Re-render history items
            renderHistoryItems();
        } catch (error) {
            SafeLogger.error('Error clearing history:', error);
            uiUtils.showError('Error clearing history: ' + error.message);
        }
    }

    // Initialize on DOM content loaded
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initializeHistory);
    } else {
        initializeHistory();
    }
})();
