import 'dart:convert'; import 'package:http/http.dart' as http; import '../models/produit.dart'; /// Résultat d'une recherche produit sur OpenFoodFacts. class InfoProduit { final String? nom; final String? imageUrl; final String? marque; final double? quantite; final String? unite; const InfoProduit({ this.nom, this.imageUrl, this.marque, this.quantite, this.unite, }); bool get estVide => (nom == null || nom!.isEmpty) && imageUrl == null; } /// Interroge l'API publique OpenFoodFacts pour récupérer le nom, l'image et la /// quantité (grammage / litrage) d'un produit à partir de son code-barres. class OpenFoodFactsService { static const String _base = 'https://world.openfoodfacts.org/api/v2/product'; Future chercherParCodeBarres(String codeBarres) async { final uri = Uri.parse( '$_base/$codeBarres.json?fields=product_name,product_name_fr,brands,' 'image_front_url,image_url,product_quantity,product_quantity_unit', ); try { final res = await http .get(uri, headers: {'User-Agent': 'GestionPrixProduit/1.0'}) .timeout(const Duration(seconds: 8)); if (res.statusCode != 200) return null; final data = jsonDecode(res.body) as Map; // status == 1 => produit trouvé if (data['status'] != 1) return const InfoProduit(); final p = data['product'] as Map? ?? {}; final nom = (p['product_name_fr'] as String?)?.trim(); final nomEn = (p['product_name'] as String?)?.trim(); final image = (p['image_front_url'] as String?)?.trim() ?? (p['image_url'] as String?)?.trim(); final (quantite, unite) = _quantite(p); return InfoProduit( nom: (nom != null && nom.isNotEmpty) ? nom : nomEn, imageUrl: (image != null && image.isNotEmpty) ? image : null, marque: (p['brands'] as String?)?.split(',').first.trim(), quantite: quantite, unite: unite, ); } catch (_) { // Pas de réseau ou timeout : on retourne null, l'utilisateur saisit à la main. return null; } } /// Normalise la quantité OpenFoodFacts (product_quantity + unité) vers nos unités. (double?, String?) _quantite(Map p) { final q = (p['product_quantity'] as num?)?.toDouble(); final u = (p['product_quantity_unit'] as String?)?.toLowerCase().trim(); if (q == null || q <= 0 || u == null) return (null, null); return switch (u) { 'g' => (q, Unites.g), 'kg' => (q, Unites.kg), 'mg' => (q / 1000, Unites.g), 'ml' => (q, Unites.ml), 'cl' => (q, Unites.cl), 'l' => (q, Unites.l), _ => (null, null), }; } }