import { NextRequest, NextResponse } from "next/server"; import { jsonCacheManager } from "@/lib/jsonCacheManager"; import { buildOffSearchParams, fetchOffProducts, parsePagination } from "@/lib/offSearch"; import type { Product } from "@/lib/openFoodFactsApi"; import { sortByRelevance } from "@/lib/searchUtils"; type LocalResults = Awaited>; function isCacheOnly(searchParams: URLSearchParams): boolean { return searchParams.get("cache_only") === "true" || process.env.NEXT_PUBLIC_CACHE_ONLY_MODE === "true"; } /** Complementa o cache com a API externa quando ele não alcança o tamanho da página. */ async function loadApiProducts( query: string, params: URLSearchParams, localCount: number, pageSize: number ): Promise { if (localCount >= pageSize) return []; console.log(`Cache JSON retornou ${localCount} produtos, buscando na API externa...`); const fetched = await fetchOffProducts(params, pageSize - localCount); if (fetched.length === 0) return []; const apiProducts = sortByRelevance(fetched, query); const saveResult = await jsonCacheManager.saveProducts(apiProducts); console.log(`Cache JSON atualizado: ${saveResult.saved} salvos, ${saveResult.failed} falharam`); return apiProducts; } function buildSearchResponse( query: string, localResults: LocalResults, apiProducts: Product[], page: number, pageSize: number ) { const localCodes = new Set(localResults.products.map((p) => p.code)); const newApiProducts = apiProducts.filter((p) => !localCodes.has(p.code)); const allProducts = [...localResults.products, ...newApiProducts]; const paginated = sortByRelevance(allProducts, query).slice(0, pageSize); console.log( `Busca finalizada: ${paginated.length} produtos (${localResults.products.length} do cache JSON, ${newApiProducts.length} novos da API)` ); return { products: paginated, count: allProducts.length, page, page_size: pageSize, skip: (page - 1) * pageSize, fromCache: localResults.fromCache, fromAPI: apiProducts.length > 0, cacheStats: { localProducts: localResults.products.length, apiProducts: apiProducts.length, newProducts: newApiProducts.length, totalReturned: paginated.length, }, }; } function errorResponse(page: number, pageSize: number) { return NextResponse.json( { products: [], count: 0, page, page_size: pageSize, skip: (page - 1) * pageSize, fromCache: false, fromAPI: false, error: "Erro interno do servidor", cacheStats: { localProducts: 0, apiProducts: 0, newProducts: 0, totalReturned: 0 }, }, { status: 500 } ); } export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const query = searchParams.get("q"); const country = searchParams.get("country"); if (!query) { return NextResponse.json({ error: "Query parameter is required" }, { status: 400 }); } const pagination = parsePagination(searchParams); if ("error" in pagination) { return NextResponse.json({ error: pagination.error }, { status: 400 }); } const { page, pageSize, pageParam } = pagination; try { console.log(`[API] Iniciando busca: "${query}" (país: ${country || "todos"}, page_size: ${pageSize})`); const localResults = await jsonCacheManager.searchProducts(query, country || undefined, pageSize); if (isCacheOnly(searchParams)) { console.log(`[Cache-Only Mode] Retornando apenas ${localResults.products.length} produtos do cache`); return NextResponse.json({ products: localResults.products, count: localResults.products.length, page, page_size: pageSize, fromCache: true, fromAPI: false, cacheOnly: true, }); } const params = buildOffSearchParams(searchParams, query, country, pageParam); const apiProducts = await loadApiProducts(query, params, localResults.products.length, pageSize); return NextResponse.json(buildSearchResponse(query, localResults, apiProducts, page, pageSize)); } catch (error) { console.error("[API] Erro ao buscar produtos:", error); return errorResponse(page, pageSize); } }