// Search Service

import { FeedItem, SearchFilters, SearchSortOption, SearchResult } from '@/types/feed';
import { getDb } from './database';

export interface SearchOptions {
  filters?: SearchFilters;
  sort?: SearchSortOption;
  page?: number;
  pageSize?: number;
}

export async function searchArticles(
  query: string,
  options: SearchOptions = {}
): Promise<SearchResult[]> {
  if (!query || query.trim().length === 0) {
    return [];
  }

  const database = await getDb();
  const { filters = {}, sort = 'relevance', page = 1, pageSize = 20 } = options;

  const offset = (page - 1) * pageSize;

  // Build WHERE clause for filters
  const whereClauses: string[] = [];
  const params: any[] = [];

  // Date filters
  if (filters.dateFrom) {
    whereClauses.push('f.published >= ?');
    params.push(filters.dateFrom.toISOString());
  }
  if (filters.dateTo) {
    whereClauses.push('f.published <= ?');
    params.push(filters.dateTo.toISOString());
  }

  // Feed filters
  if (filters.feedIds && filters.feedIds.length > 0) {
    const placeholders = filters.feedIds.map(() => '?').join(',');
    whereClauses.push(`f.subscription_id IN (${placeholders})`);
    params.push(...filters.feedIds);
  }

  // Author filters
  if (filters.authors && filters.authors.length > 0) {
    const placeholders = filters.authors.map(() => '?').join(',');
    whereClauses.push(`f.author IN (${placeholders})`);
    params.push(...filters.authors);
  }

  // Content type filter
  if (filters.contentType === 'audio') {
    whereClauses.push('(f.content LIKE "%enclosure%" OR f.description LIKE "%enclosure%")');
  } else if (filters.contentType === 'video') {
    whereClauses.push('(f.content LIKE "%video%" OR f.description LIKE "%video%")');
  }

  const whereClause = whereClauses.length > 0 
    ? `WHERE ${whereClauses.join(' AND ')}` 
    : '';

  // Build ORDER BY clause
  let orderByClause = '';
  switch (sort) {
    case 'date_desc':
      orderByClause = 'ORDER BY f.published DESC';
      break;
    case 'date_asc':
      orderByClause = 'ORDER BY f.published ASC';
      break;
    case 'title_asc':
      orderByClause = 'ORDER BY f.title ASC';
      break;
    case 'title_desc':
      orderByClause = 'ORDER BY f.title DESC';
      break;
    case 'feed_asc':
      orderByClause = 'ORDER BY s.title ASC';
      break;
    case 'feed_desc':
      orderByClause = 'ORDER BY s.title DESC';
      break;
    case 'relevance':
    default:
      // For relevance, we rely on FTS ranking
      break;
  }

  // Use FTS for full-text search when available
  let results: any[] = [];
  
  try {
    // Try FTS search first
    const ftsQuery = `SELECT f.rowid, f.rank FROM feeds_fts 
                       WHERE feeds_fts MATCH ? ${whereClause}`;
    
    const ftsResults = await database.getAllAsync<any>(ftsQuery, [...params, query]);
    
    if (ftsResults.length > 0) {
      const rowIds = ftsResults.map((r: any) => r.rowid);
      const placeholders = rowIds.map(() => '?').join(',');
      
      const selectQuery = `
        SELECT f.*, s.title as subscription_title, feeds_fts.rank
        FROM feeds f
        INNER JOIN feeds_fts ON f.rowid = feeds_fts.rowid
        LEFT JOIN subscriptions s ON f.subscription_id = s.id
        WHERE f.rowid IN (${placeholders})
        ${orderByClause || 'ORDER BY feeds_fts.rank'}
        LIMIT ? OFFSET ?
      `;
      
      results = await database.getAllAsync<any>(
        selectQuery,
        [...rowIds, pageSize, offset]
      );
    }
  } catch (error) {
    // Fallback to LIKE search if FTS fails
    console.warn('FTS search failed, falling back to LIKE search:', error);
    
    const likeQuery = `
      SELECT f.*, s.title as subscription_title
      FROM feeds f
      LEFT JOIN subscriptions s ON f.subscription_id = s.id
      ${whereClause}
      WHERE f.title LIKE ? OR f.description LIKE ? OR f.content LIKE ?
      ${orderByClause}
      LIMIT ? OFFSET ?
    `;
    
    const likeParams = [
      `%${query}%`,
      `%${query}%`,
      `%${query}%`,
      ...params,
      pageSize,
      offset
    ];
    
    results = await database.getAllAsync<any>(likeQuery, likeParams);
  }

  return results.map(row => ({
    id: row.id,
    type: 'article' as const,
    title: row.title || 'Untitled',
    snippet: extractSnippet(row.title, row.description, row.content, query),
    link: row.link,
    feedTitle: row.subscription_title,
    published: row.published ? new Date(row.published) : undefined,
    score: row.rank !== undefined ? row.rank : undefined,
  }));
}

export async function searchFeeds(
  query: string,
  limit: number = 10
): Promise<SearchResult[]> {
  if (!query || query.trim().length === 0) {
    return [];
  }

  const database = await getDb();

  try {
    // Try FTS search first
    const ftsQuery = `SELECT s.rowid, s.title, s.url, subscriptions_fts.rank 
                       FROM subscriptions s
                       INNER JOIN subscriptions_fts ON s.rowid = subscriptions_fts.rowid
                       WHERE subscriptions_fts MATCH ?
                       ORDER BY subscriptions_fts.rank
                       LIMIT ?`;
    
    const ftsResults = await database.getAllAsync<any>(ftsQuery, [query, limit]);
    
    return ftsResults.map((row: any) => ({
      id: row.rowid.toString(),
      type: 'feed' as const,
      title: row.title || 'Untitled Feed',
      link: row.url,
      score: row.rank !== undefined ? row.rank : undefined,
    }));
  } catch (error) {
    // Fallback to LIKE search if FTS fails
    console.warn('FTS feed search failed, falling back to LIKE search:', error);
    
    const likeQuery = `
      SELECT id, title, url
      FROM subscriptions
      WHERE title LIKE ? OR url LIKE ?
      LIMIT ?
    `;
    
    const likeResults = await database.getAllAsync<any>(
      likeQuery,
      [`%${query}%`, `%${query}%`, limit]
    );
    
    return likeResults.map((row: any) => ({
      id: row.id,
      type: 'feed' as const,
      title: row.title || 'Untitled Feed',
      link: row.url,
    }));
  }
}

export async function combinedSearch(
  query: string,
  options: SearchOptions = {}
): Promise<{ articles: SearchResult[]; feeds: SearchResult[] }> {
  const [articles, feeds] = await Promise.all([
    searchArticles(query, options),
    searchFeeds(query, options.pageSize || 10)
  ]);

  return { articles, feeds };
}

// Helper function to extract a snippet highlighting the search terms
function extractSnippet(
  title: string | null,
  description: string | null,
  content: string | null,
  query: string
): string | undefined {
  const texts = [
    title || '',
    description || '',
    content || ''
  ].filter(Boolean);

  if (texts.length === 0) return undefined;

  const queryLower = query.toLowerCase();
  const words = queryLower.split(/\s+/).filter(w => w.length > 0);
  
  for (const text of texts) {
    const textLower = text.toLowerCase();
    const matchIndex = words.some(word => textLower.includes(word)) 
      ? textLower.indexOf(words.find(w => textLower.includes(w)) || '') 
      : -1;
    
    if (matchIndex >= 0) {
      const start = Math.max(0, matchIndex - 50);
      const end = Math.min(text.length, matchIndex + query.length + 100);
      let snippet = text.substring(start, end);
      
      if (start > 0) snippet = '...' + snippet;
      if (end < text.length) snippet = snippet + '...';
      
      return snippet.trim();
    }
  }

  // Fallback to first 150 chars of description or content
  const fallback = description || content || title || '';
  if (fallback.length > 150) {
    return fallback.substring(0, 150).trim() + '...';
  }
  return fallback.trim() || undefined;
}
