import 'dart:convert'; /// Represents a recipe with metadata. class RecipeModel { /// Unique identifier for the recipe. final String id; /// Recipe title. final String title; /// Recipe description. final String? description; /// List of tags. final List tags; /// Rating (0-5). final int rating; /// Whether the recipe is marked as favourite. final bool isFavourite; /// List of image URLs (from Immich/Blossom). final List imageUrls; /// List of video URLs (from Blossom). final List videoUrls; /// Timestamp when recipe was created (milliseconds since epoch). final int createdAt; /// Timestamp when recipe was last updated (milliseconds since epoch). final int updatedAt; /// Whether the recipe has been deleted. final bool isDeleted; /// Nostr event ID if synced to Nostr. final String? nostrEventId; /// Creates a [RecipeModel] instance. RecipeModel({ required this.id, required this.title, this.description, List? tags, this.rating = 0, this.isFavourite = false, List? imageUrls, List? videoUrls, int? createdAt, int? updatedAt, this.isDeleted = false, this.nostrEventId, }) : tags = tags ?? [], imageUrls = imageUrls ?? [], videoUrls = videoUrls ?? [], createdAt = createdAt ?? DateTime.now().millisecondsSinceEpoch, updatedAt = updatedAt ?? DateTime.now().millisecondsSinceEpoch; /// Creates a [RecipeModel] from a database row (Map). factory RecipeModel.fromMap(Map map) { return RecipeModel( id: map['id'] as String, title: map['title'] as String, description: map['description'] as String?, tags: map['tags'] != null ? (jsonDecode(map['tags'] as String) as List) .map((e) => e.toString()) .toList() : [], rating: map['rating'] as int? ?? 0, isFavourite: (map['is_favourite'] as int? ?? 0) == 1, imageUrls: map['image_urls'] != null ? (jsonDecode(map['image_urls'] as String) as List) .map((e) => e.toString()) .toList() : [], videoUrls: map['video_urls'] != null ? (jsonDecode(map['video_urls'] as String) as List) .map((e) => e.toString()) .toList() : [], createdAt: map['created_at'] as int, updatedAt: map['updated_at'] as int, isDeleted: (map['is_deleted'] as int? ?? 0) == 1, nostrEventId: map['nostr_event_id'] as String?, ); } /// Converts the [RecipeModel] to a Map for database storage. Map toMap() { return { 'id': id, 'title': title, 'description': description, 'tags': jsonEncode(tags), 'rating': rating, 'is_favourite': isFavourite ? 1 : 0, 'image_urls': jsonEncode(imageUrls), 'video_urls': jsonEncode(videoUrls), 'created_at': createdAt, 'updated_at': updatedAt, 'is_deleted': isDeleted ? 1 : 0, 'nostr_event_id': nostrEventId, }; } /// Creates a [RecipeModel] from JSON (for Nostr content). factory RecipeModel.fromJson(Map json) { return RecipeModel( id: json['id'] as String, title: json['title'] as String, description: json['description'] as String?, tags: (json['tags'] as List?)?.map((e) => e.toString()).toList() ?? [], rating: json['rating'] as int? ?? 0, isFavourite: json['isFavourite'] as bool? ?? false, imageUrls: (json['imageUrls'] as List?)?.map((e) => e.toString()).toList() ?? [], videoUrls: (json['videoUrls'] as List?)?.map((e) => e.toString()).toList() ?? [], createdAt: json['createdAt'] as int? ?? DateTime.now().millisecondsSinceEpoch, updatedAt: json['updatedAt'] as int? ?? DateTime.now().millisecondsSinceEpoch, isDeleted: json['isDeleted'] as bool? ?? false, nostrEventId: json['nostrEventId'] as String?, ); } /// Converts the [RecipeModel] to JSON (for Nostr content). Map toJson() { return { 'id': id, 'title': title, if (description != null) 'description': description, 'tags': tags, 'rating': rating, 'isFavourite': isFavourite, 'imageUrls': imageUrls, 'videoUrls': videoUrls, 'createdAt': createdAt, 'updatedAt': updatedAt, 'isDeleted': isDeleted, if (nostrEventId != null) 'nostrEventId': nostrEventId, }; } /// Creates a copy of this [RecipeModel] with updated fields. RecipeModel copyWith({ String? id, String? title, String? description, List? tags, int? rating, bool? isFavourite, List? imageUrls, List? videoUrls, int? createdAt, int? updatedAt, bool? isDeleted, String? nostrEventId, }) { return RecipeModel( id: id ?? this.id, title: title ?? this.title, description: description ?? this.description, tags: tags ?? this.tags, rating: rating ?? this.rating, isFavourite: isFavourite ?? this.isFavourite, imageUrls: imageUrls ?? this.imageUrls, videoUrls: videoUrls ?? this.videoUrls, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, isDeleted: isDeleted ?? this.isDeleted, nostrEventId: nostrEventId ?? this.nostrEventId, ); } @override String toString() { return 'RecipeModel(id: $id, title: $title, tags: ${tags.length}, rating: $rating, favourite: $isFavourite)'; } }