/**
 * Library Semantic Search Module
 *
 * Provides semantic search for the library page and collection details:
 * - Perform semantic search against a collection
 * - Search across all indexed collections in parallel
 * - Render semantic search results with library-specific card config
 *
 * Exposed via window.LibrarySearch
 */
(function() {

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

// State
let defaultCollectionId = null;
let collectionsData = [];

/**
 * File type to Font Awesome icon mapping.
 */
function fileTypeIcon(fileType) {
    if (!fileType) return 'file';
    const ft = fileType.toLowerCase();
    if (ft === 'pdf') return 'file-pdf';
    if (ft === 'txt') return 'file-alt';
    if (ft === 'md' || ft === 'markdown') return 'file-code';
    if (ft === 'html') return 'file-code';
    return 'file';
}

/**
 * Card configuration for library documents.
 * Used by SemanticSearch.createSemanticResultCard().
 */
const LIBRARY_CARD_CONFIG = {
    getId(r) { return r.document_id || ''; },
    getTitle(r) { return r.title || 'Untitled'; },
    getUrl(r) {
        return (typeof URLBuilder !== 'undefined' && r.document_id)
            ? URLBuilder.documentPage(r.document_id) : '#';
    },
    getBadges(r) {
        const badges = [];
        if (r.file_type) {
            badges.push({ icon: fileTypeIcon(r.file_type), label: r.file_type.toUpperCase() });
        }
        return badges.length > 0 ? badges : [{ icon: 'file', label: 'DOC' }];
    },
    getDate(r) { return r.created_at || null; },
    getSubtitle(r) { return r.domain || null; },
};

/**
 * Initialize library search with collection data.
 *
 * @param {string} defaultColId - the default library collection ID
 * @param {Array} collections - collection objects with id, indexed_document_count, etc.
 */
function initLibrarySearch(defaultColId, collections) {
    defaultCollectionId = defaultColId || null;
    collectionsData = collections || [];
}

/**
 * Get the CSRF token for POST requests.
 */
function getCsrfToken() {
    return (window.api && window.api.getCsrfToken)
        ? window.api.getCsrfToken()
        : (document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '');
}

/**
 * Perform semantic search on a single collection.
 *
 * @param {string} collectionId
 * @param {string} query
 * @param {number} [limit=20]
 * @returns {Promise<Object>} API response { success, results, query }
 */
async function performSemanticSearch(collectionId, query, limit) {
    limit ||= 20;
    const url = (typeof URLBuilder !== 'undefined')
        ? URLBuilder.build(URLS.LIBRARY_API.COLLECTION_SEARCH, collectionId)
        : '/library/api/collections/' + collectionId + '/search';

    const fetchFn = (typeof safeFetch !== 'undefined') ? safeFetch : fetch;
    const response = await fetchFn(url, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRFToken': getCsrfToken(),
        },
        body: JSON.stringify({ query, limit }),
    });

    if (!response.ok) {
        throw new Error('Search failed: ' + response.status);
    }
    return await response.json();
}

/**
 * Search across all indexed collections in parallel.
 * Deduplicates results by document_id, keeping highest similarity.
 *
 * @param {string[]} collectionIds - IDs of indexed collections to search
 * @param {string} query
 * @param {number} [limit=20]
 * @returns {Promise<Array>} merged, deduplicated results sorted by similarity DESC
 */
async function searchAllCollections(collectionIds, query, limit) {
    limit ||= 20;
    if (!collectionIds || collectionIds.length === 0) return [];

    // Search in batches to avoid overwhelming the server
    const BATCH_SIZE = 3;
    const allResponses = [];
    for (let i = 0; i < collectionIds.length; i += BATCH_SIZE) {
        const batch = collectionIds.slice(i, i + BATCH_SIZE);
        const promises = batch.map(function(cid) {
            return performSemanticSearch(cid, query, limit).catch(function(err) {
                if (typeof SafeLogger !== 'undefined') {
                    SafeLogger.warn('Search failed for collection ' + cid + ':', err);
                }
                return { success: false, results: [] };
            });
        });
        const batchResponses = await Promise.all(promises);
        allResponses.push(...batchResponses);
    }

    // Merge and deduplicate by document_id, keep highest similarity
    const docMap = new Map();
    for (const resp of allResponses) {
        if (!resp.success || !Array.isArray(resp.results)) continue;
        for (const result of resp.results) {
            if (!result.document_id) continue;
            const docId = String(result.document_id);
            const existing = docMap.get(docId);
            if (!existing || result.similarity > existing.similarity) {
                docMap.set(docId, result);
            }
        }
    }

    // Sort by similarity descending and limit
    return Array.from(docMap.values())
        .sort(function(a, b) { return b.similarity - a.similarity; })
        .slice(0, limit);
}

/**
 * Render semantic search results into a container.
 *
 * @param {Array} results - search results from API
 * @param {HTMLElement} container - target container element
 */
function renderSemanticResults(results, container, query) {
    if (!container) return;

    if (!results || results.length === 0) {
        // bearer:disable javascript_lang_dangerous_insert_html
        container.innerHTML = '<div class="ldr-empty-state"><i class="fas fa-search fa-2x"></i><p>No matching results found.</p></div>';
        return;
    }

    const createCard = (window.SemanticSearch && window.SemanticSearch.createSemanticResultCard);

    if (!createCard) {
        // bearer:disable javascript_lang_dangerous_insert_html
        container.innerHTML = '<div class="ldr-empty-state"><i class="fas fa-exclamation-triangle fa-2x"></i><p>Search module not loaded. Please refresh the page.</p></div>';
        return;
    }

    const fragment = document.createDocumentFragment();
    for (const result of results) {
        fragment.appendChild(createCard(result, LIBRARY_CARD_CONFIG, query));
    }

    container.innerHTML = '';
    container.appendChild(fragment);
}

/**
 * Get IDs of all indexed collections from stored data.
 *
 * @returns {string[]} collection IDs where indexed_document_count > 0
 */
function getIndexedCollectionIds() {
    return collectionsData
        .filter(function(c) { return (c.indexed_document_count || 0) > 0; })
        .map(function(c) { return c.id; });
}

/**
 * Get the default library collection ID.
 */
function getDefaultCollectionId() {
    return defaultCollectionId;
}

// Expose public API
window.LibrarySearch = {
    initLibrarySearch,
    performSemanticSearch,
    searchAllCollections,
    renderSemanticResults,
    getIndexedCollectionIds,
    getDefaultCollectionId,
    getLibraryCardConfig() { return LIBRARY_CARD_CONFIG; },
};

})();
