import type { EnhancedProductAnalysis, SearchConfig, GeneratedQuery, SearchStrategy, PlatformId } from './types' export function getDefaultPlatforms(): Record { return { reddit: { name: 'Reddit', icon: 'MessageSquare', rateLimit: 30, enabled: true, searchTemplate: '{site} {term} {intent}', }, twitter: { name: 'X/Twitter', icon: 'Twitter', rateLimit: 20, enabled: true, searchTemplate: '{site} {term} {intent}', }, hackernews: { name: 'Hacker News', icon: 'HackerIcon', rateLimit: 30, enabled: true, searchTemplate: '{site} ("Ask HN" OR "Show HN") {term} {intent}', }, indiehackers: { name: 'Indie Hackers', icon: 'Users', rateLimit: 20, enabled: false, searchTemplate: '{site} {term} {intent}', }, quora: { name: 'Quora', icon: 'HelpCircle', rateLimit: 20, enabled: false, searchTemplate: '{site} {term} {intent}', }, stackoverflow: { name: 'Stack Overflow', icon: 'Filter', rateLimit: 30, enabled: false, searchTemplate: '{site} {term} {intent}', }, linkedin: { name: 'LinkedIn', icon: 'Globe', rateLimit: 15, enabled: false, searchTemplate: '{site} {term} {intent}', } } } export function generateSearchQueries( analysis: EnhancedProductAnalysis, config: SearchConfig ): GeneratedQuery[] { const queries: GeneratedQuery[] = [] const enabledPlatforms = config.platforms.filter(p => p.enabled) enabledPlatforms.forEach(platform => { config.strategies.forEach(strategy => { const strategyQueries = buildStrategyQueries(strategy, analysis, platform) queries.push(...strategyQueries) }) }) const deduped = sortAndDedupeQueries(queries) const limited = deduped.slice(0, config.maxResults || 50) console.info( `[opportunities] queries: generated=${queries.length} deduped=${deduped.length} limited=${limited.length}` ) return limited } function buildStrategyQueries( strategy: SearchStrategy, analysis: EnhancedProductAnalysis, platform: { id: PlatformId; searchTemplate?: string } ): GeneratedQuery[] { switch (strategy) { case 'direct-keywords': return buildDirectKeywordQueries(analysis, platform) case 'problem-pain': return buildProblemQueries(analysis, platform) case 'competitor-alternative': return buildCompetitorQueries(analysis, platform) case 'how-to': return buildHowToQueries(analysis, platform) case 'emotional-frustrated': return buildEmotionalQueries(analysis, platform) case 'comparison': return buildComparisonQueries(analysis, platform) case 'recommendation': return buildRecommendationQueries(analysis, platform) default: return [] } } function buildDirectKeywordQueries( analysis: EnhancedProductAnalysis, platform: { id: PlatformId; searchTemplate?: string } ): GeneratedQuery[] { const keywords = analysis.keywords .filter(k => k.type === 'product' || k.type === 'feature' || k.type === 'solution') .slice(0, 8) const intentPhrases = [ '("looking for" OR "need" OR "recommendation")', '("what do you use" OR "suggestions")', '("any alternatives" OR "best tool")', ] return keywords.flatMap((kw) => intentPhrases.map((intent) => ({ query: buildPlatformQuery(platform, quoteTerm(kw.term), intent), platform: platform.id, strategy: 'direct-keywords' as SearchStrategy, priority: 3, expectedIntent: 'looking' })) ) } function buildProblemQueries( analysis: EnhancedProductAnalysis, platform: { id: PlatformId; searchTemplate?: string } ): GeneratedQuery[] { const problems = analysis.problemsSolved .filter((p) => p.severity === 'high' || p.severity === 'medium') .slice(0, 6) const intentPhrases = [ '("how do I" OR "how to" OR "fix")', '("frustrated" OR "stuck" OR "struggling")', '("best way" OR "recommendation")', ] return problems.flatMap((problem) => { const terms = problem.searchTerms && problem.searchTerms.length > 0 ? problem.searchTerms.slice(0, 3) : [problem.problem] return terms.flatMap((term) => intentPhrases.map((intent) => ({ query: buildPlatformQuery(platform, quoteTerm(term), intent), platform: platform.id, strategy: 'problem-pain' as SearchStrategy, priority: 5, expectedIntent: 'frustrated', })) ) }) } function buildCompetitorQueries( analysis: EnhancedProductAnalysis, platform: { id: PlatformId; searchTemplate?: string } ): GeneratedQuery[] { const competitors = analysis.competitors .filter((comp) => comp.name && comp.name.length > 2) .slice(0, 6) const switchIntent = '("switching" OR "moving from" OR "left" OR "canceling")' const compareIntent = '("vs" OR "versus" OR "compared to" OR "better than")' const painIntent = '("frustrated" OR "issues with" OR "problems with")' return competitors.flatMap((comp) => [ { query: buildPlatformQuery(platform, quoteTerm(comp.name), switchIntent), platform: platform.id, strategy: 'competitor-alternative' as SearchStrategy, priority: 5, expectedIntent: 'comparing', }, { query: buildPlatformQuery(platform, quoteTerm(comp.name), compareIntent), platform: platform.id, strategy: 'competitor-alternative' as SearchStrategy, priority: 4, expectedIntent: 'comparing', }, { query: buildPlatformQuery(platform, quoteTerm(comp.name), painIntent), platform: platform.id, strategy: 'competitor-alternative' as SearchStrategy, priority: 5, expectedIntent: 'frustrated', }, ]) } function buildHowToQueries( analysis: EnhancedProductAnalysis, platform: { id: PlatformId; searchTemplate?: string } ): GeneratedQuery[] { const keywords = analysis.keywords .filter(k => k.type === 'feature' || k.type === 'solution') .slice(0, 6) return keywords.map(kw => ({ query: buildPlatformQuery( platform, `"how to" ${quoteTerm(kw.term)}`, '("tutorial" OR "guide" OR "help")' ), platform: platform.id, strategy: 'how-to', priority: 2, expectedIntent: 'learning' })) } function buildEmotionalQueries( analysis: EnhancedProductAnalysis, platform: { id: PlatformId; searchTemplate?: string } ): GeneratedQuery[] { const keywords = analysis.keywords .filter(k => k.type === 'product' || k.type === 'problem') .slice(0, 5) const emotionalTerms = ['frustrated', 'hate', 'sucks', 'terrible', 'annoying', 'fed up', 'tired of'] return keywords.flatMap(kw => emotionalTerms.slice(0, 3).map(term => ({ query: buildPlatformQuery(platform, quoteTerm(kw.term), term), platform: platform.id, strategy: 'emotional-frustrated', priority: 4, expectedIntent: 'frustrated' })) ) } function buildComparisonQueries( analysis: EnhancedProductAnalysis, platform: { id: PlatformId; searchTemplate?: string } ): GeneratedQuery[] { const keywords = analysis.keywords .filter(k => k.type === 'product' || k.type === 'differentiator') .slice(0, 4) return keywords.map(kw => ({ query: buildPlatformQuery(platform, quoteTerm(kw.term), '("vs" OR "versus" OR "or" OR "comparison")'), platform: platform.id, strategy: 'comparison', priority: 3, expectedIntent: 'comparing' })) } function buildRecommendationQueries( analysis: EnhancedProductAnalysis, platform: { id: PlatformId; searchTemplate?: string } ): GeneratedQuery[] { const keywords = analysis.keywords .filter(k => k.type === 'product' || k.type === 'feature') .slice(0, 5) return keywords.map(kw => ({ query: buildPlatformQuery(platform, quoteTerm(kw.term), '("what do you use" OR "recommendation" OR "suggest")'), platform: platform.id, strategy: 'recommendation', priority: 3, expectedIntent: 'recommending' })) } const SITE_OPERATORS: Record = { reddit: 'site:reddit.com', twitter: 'site:twitter.com OR site:x.com', hackernews: 'site:news.ycombinator.com', indiehackers: 'site:indiehackers.com', quora: 'site:quora.com', stackoverflow: 'site:stackoverflow.com', linkedin: 'site:linkedin.com', } const DEFAULT_TEMPLATES: Record = { reddit: '{site} {term} {intent}', twitter: '{site} {term} {intent}', hackernews: '{site} ("Ask HN" OR "Show HN") {term} {intent}', indiehackers: '{site} {term} {intent}', quora: '{site} {term} {intent}', stackoverflow: '{site} {term} {intent}', linkedin: '{site} {term} {intent}', } function applyTemplate(template: string, vars: Record): string { return template.replace(/\{(\w+)\}/g, (_match, key) => vars[key] || '') } function buildPlatformQuery( platform: { id: PlatformId; searchTemplate?: string }, term: string, intent: string ): string { const template = (platform.searchTemplate && platform.searchTemplate.trim().length > 0) ? platform.searchTemplate : DEFAULT_TEMPLATES[platform.id] const raw = applyTemplate(template, { site: SITE_OPERATORS[platform.id], term, intent, }) return raw.replace(/\s+/g, ' ').trim() } function quoteTerm(term: string): string { const cleaned = term.replace(/["]+/g, '').trim() return cleaned.includes(' ') ? `"${cleaned}"` : `"${cleaned}"` } function sortAndDedupeQueries(queries: GeneratedQuery[]): GeneratedQuery[] { // Sort by priority (high first) const sorted = queries.sort((a, b) => b.priority - a.priority) // Deduplicate by query string const seen = new Set() return sorted.filter(q => { const normalized = q.query.toLowerCase().replace(/\s+/g, ' ') if (seen.has(normalized)) return false seen.add(normalized) return true }) } export function estimateSearchTime(queryCount: number, platforms: PlatformId[]): number { const avgRateLimit = 25 // requests per minute return Math.ceil(queryCount / avgRateLimit) }