import 'dart:convert'; import 'package:uuid/uuid.dart'; import '../services/database_sync_service.dart'; import 'ingredient.dart'; class Supplement { final int? id; final String name; final String? brand; final List ingredients; final int numberOfUnits; // Number of units to take (e.g., 2 capsules) final String unitType; // capsules, tablets, ml, etc. final int frequencyPerDay; final List reminderTimes; // e.g., ['08:00', '20:00'] final String? notes; final DateTime createdAt; final bool isActive; // Sync metadata final String syncId; final DateTime lastModified; final RecordSyncStatus syncStatus; final bool isDeleted; Supplement({ this.id, required this.name, this.brand, this.ingredients = const [], required this.numberOfUnits, required this.unitType, required this.frequencyPerDay, required this.reminderTimes, this.notes, required this.createdAt, this.isActive = true, String? syncId, DateTime? lastModified, this.syncStatus = RecordSyncStatus.pending, this.isDeleted = false, }) : syncId = syncId ?? const Uuid().v4(), lastModified = lastModified ?? DateTime.now(); // Helper getters double get totalDosagePerIntake { // This concept doesn't apply well to multi-ingredient supplements // Return 0 as it should be handled per ingredient return 0.0; } // Get formatted ingredients string for display String get ingredientsDisplay { if (ingredients.isEmpty) { return 'No ingredients specified'; } return ingredients.map((ingredient) => '${ingredient.amount * numberOfUnits}${ingredient.unit} ${ingredient.name}' ).join(', '); } // Get ingredients per single unit String get ingredientsPerUnit { if (ingredients.isEmpty) { return 'No ingredients specified'; } return ingredients.map((ingredient) => ingredient.toString()).join(', '); } Map toMap() { final map = { 'name': name, 'brand': brand, 'ingredients': jsonEncode(ingredients.map((ingredient) => ingredient.toMap()).toList()), 'numberOfUnits': numberOfUnits, 'unitType': unitType, 'frequencyPerDay': frequencyPerDay, 'reminderTimes': reminderTimes.join(','), 'notes': notes, 'createdAt': createdAt.toIso8601String(), 'isActive': isActive ? 1 : 0, 'syncId': syncId, 'lastModified': lastModified.toIso8601String(), 'syncStatus': syncStatus.name, 'isDeleted': isDeleted ? 1 : 0, }; if (id != null) { map['id'] = id; } return map; } factory Supplement.fromMap(Map map) { List ingredients = []; // Try to parse ingredients if they exist if (map['ingredients'] != null && map['ingredients'].isNotEmpty) { try { final ingredientsJson = map['ingredients'] as String; final ingredientsList = jsonDecode(ingredientsJson) as List; ingredients = ingredientsList .map((ingredient) => Ingredient.fromMap(ingredient as Map)) .toList(); } catch (e) { // If parsing fails, fall back to empty list ingredients = []; } } return Supplement( id: map['id'], name: map['name'], brand: map['brand'], ingredients: ingredients, numberOfUnits: map['numberOfUnits'] ?? 1, unitType: map['unitType'] ?? 'units', frequencyPerDay: map['frequencyPerDay'], reminderTimes: map['reminderTimes'].split(','), notes: map['notes'], createdAt: DateTime.parse(map['createdAt']), isActive: map['isActive'] == 1, syncId: map['syncId'] ?? const Uuid().v4(), lastModified: map['lastModified'] != null ? DateTime.parse(map['lastModified']) : DateTime.now(), syncStatus: map['syncStatus'] != null ? RecordSyncStatus.values.firstWhere( (e) => e.name == map['syncStatus'], orElse: () => RecordSyncStatus.pending, ) : RecordSyncStatus.pending, isDeleted: (map['isDeleted'] ?? 0) == 1, ); } Supplement copyWith({ int? id, bool setNullId = false, String? name, String? brand, List? ingredients, int? numberOfUnits, String? unitType, int? frequencyPerDay, List? reminderTimes, String? notes, DateTime? createdAt, bool? isActive, String? syncId, bool newSyncId = false, DateTime? lastModified, RecordSyncStatus? syncStatus, bool? isDeleted, }) { return Supplement( id: setNullId ? null : (id ?? this.id), name: name ?? this.name, brand: brand ?? this.brand, ingredients: ingredients ?? this.ingredients, numberOfUnits: numberOfUnits ?? this.numberOfUnits, unitType: unitType ?? this.unitType, frequencyPerDay: frequencyPerDay ?? this.frequencyPerDay, reminderTimes: reminderTimes ?? this.reminderTimes, notes: notes ?? this.notes, createdAt: createdAt ?? this.createdAt, isActive: isActive ?? this.isActive, syncId: newSyncId ? null : (syncId ?? this.syncId), lastModified: lastModified ?? this.lastModified, syncStatus: syncStatus ?? this.syncStatus, isDeleted: isDeleted ?? this.isDeleted, ); } /// Create a new supplement with updated sync status and timestamp Supplement markAsModified() { return copyWith( lastModified: DateTime.now(), syncStatus: RecordSyncStatus.modified, ); } /// Create a new supplement marked as synced Supplement markAsSynced() { return copyWith( syncStatus: RecordSyncStatus.synced, ); } /// Create a new supplement marked for deletion Supplement markAsDeleted() { return copyWith( isDeleted: true, lastModified: DateTime.now(), syncStatus: RecordSyncStatus.modified, ); } }