['restaurant'], 'cafe' => ['cafe'], 'bar' => ['bar', 'night_club'], 'fast_food' => ['fast_food_restaurant', 'meal_takeaway'], 'pharmacy' => ['pharmacy'], 'hospital' => ['hospital'], 'doctor' => ['doctor'], 'bank' => ['bank', 'atm'], 'fuel' => ['gas_station'], 'supermarket' => ['supermarket'], 'hotel' => ['hotel', 'lodging'], 'government' => ['city_hall', 'government_office'], 'police' => ['police'], 'parking' => ['parking'], ]; public function nearby(string $category, float $lat, float $lng, int $radius = 2000, ?string $cuisine = null): array { $key = config('services.google.maps_key'); if (empty($key)) { Log::warning('Places: kein Google-Key, Fallback nicht möglich'); return []; } $types = self::CATEGORY_TYPES[$category] ?? ['restaurant']; try { $response = Http::timeout(10) ->withHeaders([ 'Content-Type' => 'application/json', 'X-Goog-Api-Key' => $key, 'X-Goog-FieldMask' => 'places.id,places.displayName,places.formattedAddress,places.location,places.types,places.rating', ]) ->post('https://places.googleapis.com/v1/places:searchNearby', [ 'includedTypes' => $types, 'maxResultCount' => 20, 'languageCode' => 'de', 'regionCode' => 'AT', 'locationRestriction' => [ 'circle' => [ 'center' => ['latitude' => $lat, 'longitude' => $lng], 'radius' => min((float) $radius, 50_000.0), ], ], ]); if (! $response->successful()) { Log::warning('Places API HTTP-Fehler', [ 'status' => $response->status(), 'body' => mb_substr($response->body(), 0, 200), ]); return []; } $places = $response->json('places') ?? []; // Cuisine-Filter clientseitig: Google hat keine cuisine-Tags, aber wir // können nach displayName + types filtern (z.B. "steak" enthalten). if ($cuisine !== null) { $needle = mb_strtolower($cuisine); $places = array_values(array_filter($places, function ($p) use ($needle) { $name = mb_strtolower($p['displayName']['text'] ?? ''); return str_contains($name, $needle) || str_contains($name, str_replace('_', ' ', $needle)); })); } return array_map(function ($p) use ($category) { return [ 'id' => 'gp-'.($p['id'] ?? uniqid()), 'name' => $p['displayName']['text'] ?? '?', 'address' => $p['formattedAddress'] ?? '', 'lat' => $p['location']['latitude'] ?? null, 'lng' => $p['location']['longitude'] ?? null, 'rating' => $p['rating'] ?? null, 'category' => $category, ]; }, $places); } catch (\Throwable $e) { Log::warning('Places exception', ['e' => $e->getMessage()]); return []; } } }