import { json, type RequestHandler } from '@sveltejs/kit'; import type { BriefRecipeType } from '$types/types'; import { Recipe } from '$models/Recipe'; import { dbConnect } from '$utils/db'; export const GET: RequestHandler = async ({ url, locals }) => { await dbConnect(); const query = url.searchParams.get('q')?.toLowerCase().trim() || ''; const category = url.searchParams.get('category'); // Support both single tag (backwards compat) and multiple tags const singleTag = url.searchParams.get('tag'); const multipleTags = url.searchParams.get('tags'); const tags = multipleTags ? multipleTags.split(',').map(t => t.trim()).filter(Boolean) : (singleTag ? [singleTag] : []); const icon = url.searchParams.get('icon'); // Support both single season (backwards compat) and multiple seasons const singleSeason = url.searchParams.get('season'); const multipleSeasons = url.searchParams.get('seasons'); const seasons = multipleSeasons ? multipleSeasons.split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n)) : (singleSeason ? [parseInt(singleSeason)].filter(n => !isNaN(n)) : []); const favoritesOnly = url.searchParams.get('favorites') === 'true'; try { // Build base query - only recipes with approved English translations let dbQuery: any = { 'translations.en.translationStatus': 'approved' }; // Apply filters based on context if (category) { dbQuery['translations.en.category'] = category; } // Multi-tag AND logic: recipe must have ALL selected tags if (tags.length > 0) { dbQuery['translations.en.tags'] = { $all: tags }; } if (icon) { dbQuery.icon = icon; // Icon is the same for both languages } // Multi-season OR logic: recipe in any selected season if (seasons.length > 0) { dbQuery.season = { $in: seasons }; // Season is the same for both languages } // Get all recipes matching base filters let recipes = await Recipe.find(dbQuery).lean(); // Handle favorites filter if (favoritesOnly && locals.session?.user) { const { UserFavorites } = await import('../../../../models/UserFavorites'); const userFavorites = await UserFavorites.findOne({ username: locals.session.user.username }); if (userFavorites && userFavorites.favorites) { const favoriteIds = userFavorites.favorites; recipes = recipes.filter(recipe => favoriteIds.some(id => id.toString() === recipe._id?.toString())); } else { recipes = []; } } // Transform to English brief format let briefRecipes: BriefRecipeType[] = recipes.map(recipe => ({ _id: recipe._id, name: recipe.translations.en.name, short_name: recipe.translations.en.short_name, tags: recipe.translations.en.tags || [], category: recipe.translations.en.category, icon: recipe.icon, description: recipe.translations.en.description, season: recipe.season, dateModified: recipe.dateModified, germanShortName: recipe.short_name })); // Apply text search if query provided if (query) { const searchTerms = query.normalize('NFD').replace(/\p{Diacritic}/gu, "").split(" "); briefRecipes = briefRecipes.filter(recipe => { const searchString = `${recipe.name} ${recipe.description || ''} ${recipe.tags?.join(' ') || ''}`.toLowerCase() .normalize('NFD').replace(/\p{Diacritic}/gu, "").replace(/­|­/g, ''); return searchTerms.every(term => searchString.includes(term)); }); } return json(JSON.parse(JSON.stringify(briefRecipes))); } catch (error) { return json({ error: 'Search failed' }, { status: 500 }); } };