import 'package:flutter/foundation.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import '../models/payment_method.dart'; import '../models/bar_tab.dart'; import '../models/product.dart'; import '../models/tab_item.dart'; import '../services/bar_tab_service.dart'; import '../services/product_service.dart'; import 'inventory_view_model.dart'; class BarScreenViewModel extends ChangeNotifier { final BarTabService barTabService; final InventoryViewModel inventory; BarScreenViewModel({required this.barTabService, required this.inventory}); List _tabs = []; String? _selectedTabId; bool _isLoading = false; bool _hasLoaded = false; String? _errorMessage; List get tabs => _tabs; String? get selectedTabId => _selectedTabId; bool get isLoading => _isLoading; bool get hasLoaded => _hasLoaded; String? get errorMessage => _errorMessage; BarTab? get selectedTab { if (_selectedTabId == null) return null; try { return _tabs.firstWhere((tab) => tab.id == _selectedTabId); } catch (e) { debugPrint('BarScreenViewModel: error finding selected tab: $e'); return null; } } Future ensureLoaded() async { if (_hasLoaded || _isLoading) return; await load(); } Future load() async { if (_isLoading) return; _isLoading = true; _errorMessage = null; notifyListeners(); try { _tabs = await barTabService.getOpenTabs(); if (_selectedTabId == null || !_tabs.any((tab) => tab.id == _selectedTabId)) { _selectedTabId = _tabs.isEmpty ? null : _tabs.first.id; } } catch (e) { debugPrint('BarScreenViewModel: load error: $e'); _errorMessage = 'Could not load bar screen.'; } finally { _hasLoaded = true; _isLoading = false; notifyListeners(); } } void selectTab(String tabId) { _selectedTabId = tabId; notifyListeners(); } Future createTab(String customerName) async { try { final tab = await barTabService.createTab(customerName: customerName); _selectedTabId = tab.id; await _reloadTabs(); } catch (e, stack) { debugPrint('BarScreenViewModel: createTab error: $e'); _errorMessage = 'Could not create tab.'; notifyListeners(); Sentry.captureException(e, stackTrace: stack); } } Future renameTab(String tabId, String customerName) async { try { await barTabService.renameTab(tabId: tabId, customerName: customerName); await _reloadTabs(); } catch (e, stack) { debugPrint('BarScreenViewModel: renameTab error: $e'); _errorMessage = 'Could not rename tab.'; notifyListeners(); Sentry.captureException(e, stackTrace: stack); rethrow; } } Future deleteTab(String tabId) async { try { final deletedItems = await barTabService.deleteTab(tabId); for (final item in deletedItems) { inventory.applyStockDelta(item.productId, item.quantity); } await _reloadTabs(); } catch (e, stack) { debugPrint('BarScreenViewModel: deleteTab error: $e'); _errorMessage = 'Could not delete tab.'; notifyListeners(); Sentry.captureException(e, stackTrace: stack); rethrow; } } Future addProductToSelectedTab(Product product) async { final tab = selectedTab; if (tab == null) return; try { await barTabService.addProductToTab(tabId: tab.id, product: product); inventory.applyStockDelta(product.id, -1); await _reloadTabs(); } catch (e, stack) { if (e is InsufficientStockException) rethrow; debugPrint('BarScreenViewModel: addProductToSelectedTab error: $e'); _errorMessage = 'Could not add product to tab.'; notifyListeners(); Sentry.captureException(e, stackTrace: stack); rethrow; } } Future changeItemQuantity(TabItem item, int delta) async { if (delta == 0) return; try { final actualDelta = await barTabService.adjustTabItemQuantity( tabItemId: item.id, delta: delta, ); inventory.applyStockDelta(item.productId, -actualDelta); await _reloadTabs(); } catch (e, stack) { if (e is InsufficientStockException) rethrow; debugPrint('BarScreenViewModel: changeItemQuantity error: $e'); _errorMessage = 'Could not update item quantity.'; notifyListeners(); Sentry.captureException(e, stackTrace: stack); rethrow; } } Future closeSelectedTab({ PaymentMethod paymentMethod = PaymentMethod.cash, }) async { final tab = selectedTab; if (tab == null) return; try { await barTabService.closeTab(tab.id, paymentMethod: paymentMethod); await _reloadTabs(); } catch (e, stack) { debugPrint('BarScreenViewModel: closeSelectedTab error: $e'); _errorMessage = 'Could not close tab.'; notifyListeners(); Sentry.captureException(e, stackTrace: stack); rethrow; } } Future closeTab( String tabId, { PaymentMethod paymentMethod = PaymentMethod.cash, }) async { try { await barTabService.closeTab(tabId, paymentMethod: paymentMethod); await _reloadTabs(); } catch (e, stack) { debugPrint('BarScreenViewModel: closeTab error: $e'); _errorMessage = 'Could not close tab.'; notifyListeners(); Sentry.captureException(e, stackTrace: stack); rethrow; } } Future _reloadTabs() async { try { _tabs = await barTabService.getOpenTabs(); if (_selectedTabId == null || !_tabs.any((tab) => tab.id == _selectedTabId)) { _selectedTabId = _tabs.isEmpty ? null : _tabs.first.id; } notifyListeners(); } catch (e, stack) { debugPrint('BarScreenViewModel: reloadTabs error: $e'); _errorMessage = 'Could not reload tabs.'; notifyListeners(); Sentry.captureException(e, stackTrace: stack); } } }