import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:drift/drift.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:uuid/uuid.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; import '../database/app_database.dart'; class DefaultProductSeeder { final AppDatabase database; DefaultProductSeeder({required this.database}); static const _defaultProducts = [ ('Jupiler', 280, 80, 'Bier'), ('Stella Artois', 300, 60, 'Bier'), ('Leffe Blonde', 380, 30, 'Bier'), ('Duvel', 420, 25, 'Bier'), ('Hoegaarden', 350, 35, 'Bier'), ('Witte Wijn', 380, 50, 'Wijn'), ('Rode Wijn', 400, 45, 'Wijn'), ('Rosé', 350, 40, 'Wijn'), ('Cola', 250, 100, 'Frisdrank'), ('Cola Zero', 250, 80, 'Frisdrank'), ('Spa Bruis', 200, 70, 'Frisdrank'), ('Spa Plat', 200, 70, 'Frisdrank'), ('Ice Tea', 280, 60, 'Frisdrank'), ('Limonade', 250, 50, 'Frisdrank'), ('Chips', 220, 40, 'Snacks'), ('Koffie', 280, 200, 'Coffee'), ('Thee', 250, 150, 'Coffee'), ]; Future seedIfEmpty() async { try { final count = await _getProductCount(); if (count > 0) return; final imagesDir = await _ensureImagesDir(); await database.transaction(() async { final uuid = const Uuid(); for (final (name, priceInCents, stock, category) in _defaultProducts) { String? imagePath; if (imagesDir != null) { imagePath = await _copyBundledImage(name, imagesDir); } await database.into(database.products).insert( ProductsCompanion.insert( id: uuid.v4(), name: name, category: category, stockQuantity: stock, lowStockThreshold: 10, priceInCents: priceInCents, imagePath: Value(imagePath), ), ); } }); } catch (e, stack) { debugPrint('DefaultProductSeeder: seedIfEmpty error: $e'); Sentry.captureException(e, stackTrace: stack); } } Future _getProductCount() async { final countExpr = database.products.id.count(); final query = database.selectOnly(database.products) ..addColumns([countExpr]); final row = await query.getSingle(); return row.read(countExpr) ?? 0; } Future _ensureImagesDir() async { try { final appDir = await getApplicationSupportDirectory(); final imagesDir = Directory(path.join(appDir.path, 'product_images')); if (!imagesDir.existsSync()) { await imagesDir.create(recursive: true); } return imagesDir; } catch (e) { debugPrint('DefaultProductSeeder: could not create images dir: $e'); return null; } } Future _copyBundledImage(String productName, Directory imagesDir) async { final slug = _toSlug(productName); for (final ext in ['png', 'jpg', 'webp']) { final assetKey = 'assets/products/$slug.$ext'; try { final bytes = await rootBundle.load(assetKey); final fileName = '${DateTime.now().millisecondsSinceEpoch}_$slug.$ext'; final destPath = path.join(imagesDir.path, fileName); final destFile = File(destPath); await destFile.writeAsBytes(bytes.buffer.asUint8List( bytes.offsetInBytes, bytes.lengthInBytes, )); return destPath; } catch (_) { // Asset not found for this extension, try next } } debugPrint('DefaultProductSeeder: no bundled image found for "$productName" ' '(looked for assets/products/$slug.{png,jpg,webp})'); return null; } String _toSlug(String name) { return name .toLowerCase() .replaceAll(' ', '_') .replaceAll("'", '') .replaceAll('é', 'e') .replaceAll('è', 'e') .replaceAll('ê', 'e') .replaceAll('ë', 'e') .replaceAll('â', 'a') .replaceAll('à', 'a') .replaceAll('ä', 'a') .replaceAll('û', 'u') .replaceAll('ù', 'u') .replaceAll('ü', 'u') .replaceAll('ô', 'o') .replaceAll('ö', 'o') .replaceAll('ï', 'i') .replaceAll('î', 'i') .replaceAll('ç', 'c') .replaceAll('œ', 'oe'); } }