import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; interface Business { place_id: string; name: string; address: string; rating: number; review_count: number; category: string; maps_url: string; } const GOOGLE_MAPS_URL_PATTERN = /(?:google\.com\/maps|maps\.google\.com|goo\.gl\/maps|maps\.app\.goo\.gl)/i; function isGoogleMapsUrl(input: string): boolean { return GOOGLE_MAPS_URL_PATTERN.test(input); } export async function POST(request: NextRequest) { try { const body = await request.json(); const { query } = body as { query: string }; if (!query || typeof query !== "string" || query.trim().length < 2) { return NextResponse.json( { error: "Query must be at least 2 characters" }, { status: 400 }, ); } const trimmed = query.trim(); if (isGoogleMapsUrl(trimmed)) { return handleUrlSearch(trimmed); } return handleTextSearch(trimmed); } catch { return NextResponse.json( { error: "Invalid request body" }, { status: 400 }, ); } } async function handleUrlSearch(url: string): Promise { const engineUrl = process.env.NEXT_PUBLIC_ENGINE_URL; if (!engineUrl) { return NextResponse.json( { error: "Engine service not configured" }, { status: 503 }, ); } try { const response = await fetch(`${engineUrl}/api/check-reviews`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url }), }); if (!response.ok) { return NextResponse.json( { error: "Could not find business from URL" }, { status: 404 }, ); } const data = (await response.json()) as Record; const business: Business = { place_id: (data.place_id as string) || "", name: (data.name as string) || "Unknown Business", address: (data.address as string) || "", rating: (data.rating as number) || 0, review_count: (data.review_count as number) || (data.reviews_count as number) || 0, category: (data.category as string) || (data.type as string) || "", maps_url: url, }; return NextResponse.json({ businesses: [business] }); } catch { return NextResponse.json( { error: "Failed to fetch business details" }, { status: 502 }, ); } } async function handleTextSearch(query: string): Promise { const apiKey = process.env.GOOGLE_PLACES_API_KEY; if (!apiKey) { return NextResponse.json( { error: "Places search not configured" }, { status: 503 }, ); } try { const response = await fetch( "https://places.googleapis.com/v1/places:searchText", { method: "POST", headers: { "Content-Type": "application/json", "X-Goog-Api-Key": apiKey, "X-Goog-FieldMask": "places.id,places.displayName,places.formattedAddress,places.rating,places.userRatingCount,places.primaryTypeDisplayName,places.googleMapsUri", }, body: JSON.stringify({ textQuery: query, languageCode: "en", }), }, ); if (!response.ok) { return NextResponse.json( { error: "Places search failed" }, { status: 502 }, ); } const data = (await response.json()) as Record; const businesses: Business[] = ((data.places as any[]) || []) .slice(0, 5) .map((place: any) => ({ place_id: place.id || "", name: place.displayName?.text || "Unknown", address: place.formattedAddress || "", rating: place.rating || 0, review_count: place.userRatingCount || 0, category: place.primaryTypeDisplayName?.text || "", maps_url: place.googleMapsUri || "", })); return NextResponse.json({ businesses }); } catch { return NextResponse.json( { error: "Failed to search businesses" }, { status: 502 }, ); } }