import '../../core/api/api_client.dart'; import '../../shared/models/product.dart'; /// Lightweight dish result returned by GET /dishes/search. class DishSearchResult { final String id; final String name; final String? imageUrl; final double avgRating; const DishSearchResult({ required this.id, required this.name, this.imageUrl, required this.avgRating, }); factory DishSearchResult.fromJson(Map json) { return DishSearchResult( id: json['id'] as String, name: json['name'] as String, imageUrl: json['image_url'] as String?, avgRating: (json['avg_rating'] as num?)?.toDouble() ?? 0, ); } } /// One item from GET /diary/recent. class RecentDiaryItem { final String itemType; // "dish" | "product" final String? dishId; final String? productId; final String name; final String? imageUrl; final String? categoryName; final double? caloriesPer100g; final double? caloriesPerServing; const RecentDiaryItem({ required this.itemType, this.dishId, this.productId, required this.name, this.imageUrl, this.categoryName, this.caloriesPer100g, this.caloriesPerServing, }); factory RecentDiaryItem.fromJson(Map json) { return RecentDiaryItem( itemType: json['item_type'] as String? ?? 'dish', dishId: json['dish_id'] as String?, productId: json['product_id'] as String?, name: json['name'] as String? ?? '', imageUrl: json['image_url'] as String?, categoryName: json['category_name'] as String?, caloriesPer100g: (json['calories_per_100g'] as num?)?.toDouble(), caloriesPerServing: (json['calories_per_serving'] as num?)?.toDouble(), ); } /// For products: calories per 100 g; for dishes: calories per serving. double? get displayCalories => itemType == 'product' ? caloriesPer100g : caloriesPerServing; } /// Service for searching products/dishes and loading recently used diary items. class FoodSearchService { const FoodSearchService(this._client); final ApiClient _client; /// Searches catalog products by name. Future> searchProducts(String query) async { if (query.isEmpty) return []; final list = await _client.getList( '/products/search', params: {'q': query, 'limit': '20'}, ); return list .map((item) => CatalogProduct.fromJson(item as Map)) .toList(); } /// Searches dishes by name. Future> searchDishes(String query) async { if (query.isEmpty) return []; final list = await _client.getList( '/dishes/search', params: {'q': query, 'limit': '10'}, ); return list .map((item) => DishSearchResult.fromJson(item as Map)) .toList(); } /// Returns recent diary items (dishes and products) for the current user. Future> getRecent({int limit = 10}) async { final list = await _client.getList( '/diary/recent', params: {'limit': '$limit'}, ); return list .map((item) => RecentDiaryItem.fromJson(item as Map)) .toList(); } }