import '../utils/app_config.dart'; enum CommandType { closeTab('close_tab'); final String value; const CommandType(this.value); static CommandType? fromValue(String value) { for (final type in CommandType.values) { if (type.value == value) return type; } return null; } } enum CommandResult { completed, conflict, failed, expired } class RemoteCommand { final String id; final String rawType; final String tabId; final int expectedVersion; final String paymentMethod; final String requestedBy; final DateTime createdAt; const RemoteCommand({ required this.id, required this.rawType, required this.tabId, required this.expectedVersion, required this.paymentMethod, required this.requestedBy, required this.createdAt, }); factory RemoteCommand.fromJson(Map json) { return RemoteCommand( id: json['id'] as String, rawType: json['type'] as String, tabId: json['tabId'] as String, expectedVersion: json['expectedVersion'] as int, paymentMethod: json['paymentMethod'] as String? ?? 'cash', requestedBy: json['requestedBy'] as String? ?? '', createdAt: DateTime.parse(json['createdAt'] as String), ); } /// Null when the server sends a command this app version doesn't know. CommandType? get type => CommandType.fromValue(rawType); bool get isExpired { final cutoff = DateTime.now().subtract( const Duration(hours: kCommandExpiryHours), ); return createdAt.isBefore(cutoff); } } class SyncResponse { final List commands; final String? cursor; final List plannedTabNames; const SyncResponse({ required this.commands, this.cursor, this.plannedTabNames = const [], }); factory SyncResponse.fromJson(Map json) { return SyncResponse( commands: [ for (final command in json['commands'] as List? ?? []) RemoteCommand.fromJson(command as Map), ], cursor: json['cursor'] as String?, plannedTabNames: [ for (final name in json['plannedTabNames'] as List? ?? []) name as String, ], ); } } class SnapshotTab { final String id; final String customerName; final int version; final int totalInCents; final int itemCount; const SnapshotTab({ required this.id, required this.customerName, required this.version, required this.totalInCents, required this.itemCount, }); Map toJson() => { 'id': id, 'customerName': customerName, 'version': version, 'totalInCents': totalInCents, 'itemCount': itemCount, }; } class SyncRequest { final String deviceId; final String? cursor; final List openTabs; const SyncRequest({ required this.deviceId, this.cursor, required this.openTabs, }); Map toJson() => { 'deviceId': deviceId, if (cursor != null) 'cursor': cursor, 'openTabs': openTabs.map((tab) => tab.toJson()).toList(), }; } class CommandAck { final String commandId; final CommandResult status; final String? result; const CommandAck({ required this.commandId, required this.status, this.result, }); Map toJson() => { 'commandId': commandId, 'status': status.name, if (result != null) 'result': result, }; } enum RemoteSyncEventType { tabClosedRemotely, syncCompleted, syncFailed, conflict, unauthorized, } class RemoteSyncEvent { final RemoteSyncEventType type; final String? tabCustomerName; final String? requestedBy; final String? message; const RemoteSyncEvent({ required this.type, this.tabCustomerName, this.requestedBy, this.message, }); }