const SearchManager = { availableExtensions: [], searchTimeout: null, init(inputSelector, resultsSelector, type = 'anime') { const searchInput = document.querySelector(inputSelector); const searchResults = document.querySelector(resultsSelector); if (!searchInput || !searchResults) { console.error('Search elements not found'); return; } this.loadExtensions(type); searchInput.addEventListener('input', (e) => { const query = e.target.value; clearTimeout(this.searchTimeout); if (query.length < 2) { searchResults.classList.remove('active'); searchResults.innerHTML = ''; searchInput.style.borderRadius = '99px'; return; } this.searchTimeout = setTimeout(() => { this.search(query, type, searchResults); }, 300); }); document.addEventListener('click', (e) => { if (!e.target.closest('.search-wrapper')) { searchResults.classList.remove('active'); searchInput.style.borderRadius = '99px'; } }); }, async loadExtensions(type) { try { const endpoint = type === 'book' ? '/api/extensions/book' : '/api/extensions/anime'; const res = await fetch(endpoint); const data = await res.json(); this.availableExtensions = data.extensions || []; console.log(`${type} extensions loaded:`, this.availableExtensions); } catch (err) { console.error('Error loading extensions:', err); } }, async search(query, type, resultsContainer) { try { let apiUrl, extensionName = null, finalQuery = query; const parts = query.split(':'); if (parts.length >= 2) { const potentialExtension = parts[0].trim().toLowerCase(); const foundExtension = this.availableExtensions.find( ext => ext.toLowerCase() === potentialExtension ); if (foundExtension) { extensionName = foundExtension; finalQuery = parts.slice(1).join(':').trim(); if (finalQuery.length === 0) { this.renderResults([], resultsContainer, type); return; } } } if (extensionName) { const endpoint = type === 'book' ? 'books' : ''; apiUrl = `/api/search/${endpoint ? endpoint + '/' : ''}${extensionName}?q=${encodeURIComponent(finalQuery)}`; } else { const endpoint = type === 'book' ? '/api/search/books' : '/api/search'; apiUrl = `${endpoint}?q=${encodeURIComponent(query)}`; } const res = await fetch(apiUrl); const data = await res.json(); const results = (data.results || []).map(item => ({ ...item, isExtensionResult: !!extensionName, extensionName })); this.renderResults(results, resultsContainer, type); } catch (err) { console.error("Search Error:", err); this.renderResults([], resultsContainer, type); } }, renderResults(results, container, type) { container.innerHTML = ''; if (!results || results.length === 0) { container.innerHTML = '
No results found
'; } else { results.forEach(item => { const resultElement = this.createResultElement(item, type); container.appendChild(resultElement); }); } container.classList.add('active'); const searchInput = container.previousElementSibling || document.querySelector('.search-input'); if (searchInput) { searchInput.style.borderRadius = '12px 12px 0 0'; } }, createResultElement(item, type) { const element = document.createElement('a'); element.className = 'search-item'; if (type === 'book') { const title = item.title?.english || item.title?.romaji || "Unknown"; const img = item.coverImage?.medium || item.coverImage?.large || ''; const rating = Number.isInteger(item.averageScore) ? `${item.averageScore}%` : item.averageScore || 'N/A'; const year = item.seasonYear || item.startDate?.year || '????'; const format = item.format || 'MANGA'; element.href = item.isExtensionResult ? `/book/${item.extensionName}/${item.id}` : `/book/${item.id}`; element.innerHTML = ` ${title}
${title}
${rating} • ${year} • ${format}
`; } else { const title = item.title?.english || item.title?.romaji || "Unknown Title"; const img = item.coverImage?.medium || item.coverImage?.large || ''; const rating = item.averageScore ? `${item.averageScore}%` : 'N/A'; const year = item.seasonYear || ''; const format = item.format || 'TV'; element.href = item.isExtensionResult ? `/anime/${item.extensionName}/${item.id}` : `/anime/${item.id}`; element.innerHTML = ` ${title}
${title}
${rating} • ${year} • ${format}
`; } return element; }, getTitle(item) { return item.title?.english || item.title?.romaji || "Unknown Title"; } }; window.SearchManager = SearchManager;